camstack 1.2.207 → 1.2.209

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/cli.js CHANGED
@@ -37,7 +37,7 @@ async function runServe(args) {
37
37
  ...typeof values.data === "string" ? { data: values.data } : {}
38
38
  };
39
39
  Object.assign(process.env, buildServeEnv(opts));
40
- await import("./launcher-P6ECOKBY.js");
40
+ await import("./launcher-HE66BYDV.js");
41
41
  }
42
42
 
43
43
  // src/commands/agent.ts
@@ -82,7 +82,7 @@ async function runAgent(args) {
82
82
  ...typeof values.port === "string" ? { port: values.port } : {}
83
83
  };
84
84
  Object.assign(process.env, buildAgentEnv(opts));
85
- await import("./launcher-P6ECOKBY.js");
85
+ await import("./launcher-HE66BYDV.js");
86
86
  }
87
87
 
88
88
  // src/commands/setup.ts
@@ -91,7 +91,7 @@ import * as path from "path";
91
91
  import * as fs from "fs";
92
92
  import { parseArgs as parseArgs3 } from "util";
93
93
 
94
- // ../types/dist/event-category-DHXxB8t9.mjs
94
+ // ../types/dist/event-category-CT-hz5Rb.mjs
95
95
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
96
96
  EventCategory2["SystemBoot"] = "system.boot";
97
97
  EventCategory2["SystemAddonsReady"] = "system.addons-ready";
@@ -174,6 +174,8 @@ var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
174
174
  EventCategory2["PipelineDetectionBlind"] = "pipeline.detection-blind";
175
175
  EventCategory2["PipelineMotionNoisy"] = "pipeline.motion-noisy";
176
176
  EventCategory2["PipelineMotionCalm"] = "pipeline.motion-calm";
177
+ EventCategory2["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
178
+ EventCategory2["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
177
179
  EventCategory2["PipelineCameraUpdated"] = "pipeline.camera-updated";
178
180
  EventCategory2["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
179
181
  EventCategory2["PipelineRunnerLoadSnapshot"] = "pipeline.runner-load-snapshot";
@@ -14779,7 +14781,7 @@ function date4(params) {
14779
14781
  // ../../node_modules/zod/v4/classic/external.js
14780
14782
  config(en_default());
14781
14783
 
14782
- // ../types/dist/sleep-BErAxhul.mjs
14784
+ // ../types/dist/sleep--jXS9hWo.mjs
14783
14785
  var AUDIO_CHUNK_FORMATS = [
14784
14786
  "f32le",
14785
14787
  "pcmu",
@@ -15060,6 +15062,94 @@ var RecordKindDeclarationShape = external_exports.object({
15060
15062
  });
15061
15063
  var RecordKindDeclarationSchema = RecordKindDeclarationShape.strict();
15062
15064
  var RecordKindNameSchema = external_exports.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
15065
+ var READING_QUANTITIES = [
15066
+ "temperature",
15067
+ "pressure",
15068
+ "speed",
15069
+ "precipitation",
15070
+ "precipitation-rate",
15071
+ "length",
15072
+ "area",
15073
+ "illuminance",
15074
+ "irradiance",
15075
+ "power",
15076
+ "energy",
15077
+ "voltage",
15078
+ "current",
15079
+ "apparent-power",
15080
+ "humidity",
15081
+ "percentage",
15082
+ "concentration-volume",
15083
+ "concentration-mass",
15084
+ "concentration-ppb",
15085
+ "volume",
15086
+ "duration",
15087
+ "duration-ms",
15088
+ "information",
15089
+ "sound-level",
15090
+ "signal-level",
15091
+ "colour-temperature",
15092
+ "angle",
15093
+ "bitrate",
15094
+ "rate",
15095
+ "mass",
15096
+ "index",
15097
+ "ratio",
15098
+ "count",
15099
+ "none",
15100
+ "device"
15101
+ ];
15102
+ var ReadingQuantitySchema = external_exports.enum(READING_QUANTITIES);
15103
+ var QUANTITY_SET = new Set(READING_QUANTITIES);
15104
+ var QUANTITY_BASE = {
15105
+ temperature: "\xB0C",
15106
+ pressure: "hPa",
15107
+ speed: "m/s",
15108
+ precipitation: "mm",
15109
+ "precipitation-rate": "mm/h",
15110
+ length: "m",
15111
+ area: "m\xB2",
15112
+ illuminance: "lx",
15113
+ irradiance: "W/m\xB2",
15114
+ power: "W",
15115
+ energy: "kWh",
15116
+ voltage: "V",
15117
+ current: "A",
15118
+ "apparent-power": "VA",
15119
+ humidity: "%",
15120
+ percentage: "%",
15121
+ "concentration-volume": "ppm",
15122
+ "concentration-mass": "\xB5g/m\xB3",
15123
+ "concentration-ppb": "ppb",
15124
+ volume: "L",
15125
+ duration: "s",
15126
+ "duration-ms": "ms",
15127
+ information: "B",
15128
+ "sound-level": "dBFS",
15129
+ "signal-level": "dBm",
15130
+ "colour-temperature": "mired",
15131
+ angle: "\xB0",
15132
+ bitrate: "kbps",
15133
+ rate: "fps",
15134
+ mass: "kg",
15135
+ index: "none",
15136
+ ratio: "none",
15137
+ count: "none",
15138
+ none: "none",
15139
+ device: "device"
15140
+ };
15141
+ function baseUnitOf(quantity) {
15142
+ const symbol2 = QUANTITY_BASE[quantity];
15143
+ if (symbol2 === "none" || symbol2 === "device") return void 0;
15144
+ return symbol2;
15145
+ }
15146
+ function readingMeta(quantity, extras) {
15147
+ return {
15148
+ quantity,
15149
+ ...extras?.precision !== void 0 ? { precision: extras.precision } : {},
15150
+ ...extras?.label !== void 0 ? { label: extras.label } : {}
15151
+ };
15152
+ }
15063
15153
  var CamProfileSchema = external_exports.enum([
15064
15154
  "high",
15065
15155
  "mid",
@@ -15076,8 +15166,8 @@ var CamStreamKindSchema = external_exports.enum([
15076
15166
  "derived"
15077
15167
  ]);
15078
15168
  var CamStreamResolutionSchema = external_exports.object({
15079
- width: external_exports.number().int().positive(),
15080
- height: external_exports.number().int().positive()
15169
+ width: external_exports.number().int().positive().meta(readingMeta("none")),
15170
+ height: external_exports.number().int().positive().meta(readingMeta("none"))
15081
15171
  });
15082
15172
  var CameraStreamSchema = external_exports.object({
15083
15173
  /** Stable, provider-assigned id unique within the (deviceId) scope. */
@@ -15627,6 +15717,9 @@ var CAP_NAMES = Object.freeze([
15627
15717
  "filesystem-browse",
15628
15718
  "flood",
15629
15719
  "gas",
15720
+ "group-active",
15721
+ "group-commands",
15722
+ "group-status",
15630
15723
  "heating-valve",
15631
15724
  "humidifier",
15632
15725
  "humidity-sensor",
@@ -15647,6 +15740,7 @@ var CAP_NAMES = Object.freeze([
15647
15740
  "login-method",
15648
15741
  "media-player",
15649
15742
  "mesh-network",
15743
+ "meter",
15650
15744
  "metrics-provider",
15651
15745
  "model-convert",
15652
15746
  "model-distributor",
@@ -15756,14 +15850,6 @@ var CAP_STATE_LEAVES = Object.freeze({
15756
15850
  {
15757
15851
  "path": "aqi",
15758
15852
  "valueType": "number"
15759
- },
15760
- {
15761
- "path": "unit",
15762
- "valueType": "string"
15763
- },
15764
- {
15765
- "path": "precision",
15766
- "valueType": "number"
15767
15853
  }
15768
15854
  ],
15769
15855
  "alarm-panel": [
@@ -15799,20 +15885,10 @@ var CAP_STATE_LEAVES = Object.freeze({
15799
15885
  "valueType": "boolean"
15800
15886
  }
15801
15887
  ],
15802
- "ambient-light-sensor": [
15803
- {
15804
- "path": "lux",
15805
- "valueType": "number"
15806
- },
15807
- {
15808
- "path": "unit",
15809
- "valueType": "string"
15810
- },
15811
- {
15812
- "path": "precision",
15813
- "valueType": "number"
15814
- }
15815
- ],
15888
+ "ambient-light-sensor": [{
15889
+ "path": "lux",
15890
+ "valueType": "number"
15891
+ }],
15816
15892
  "audio-metrics": [
15817
15893
  {
15818
15894
  "path": "ts",
@@ -15892,6 +15968,10 @@ var CAP_STATE_LEAVES = Object.freeze({
15892
15968
  "path": "lastUpdated",
15893
15969
  "valueType": "number"
15894
15970
  },
15971
+ {
15972
+ "path": "volts",
15973
+ "valueType": "number"
15974
+ },
15895
15975
  {
15896
15976
  "path": "lastContactAt",
15897
15977
  "valueType": "number"
@@ -16134,10 +16214,6 @@ var CAP_STATE_LEAVES = Object.freeze({
16134
16214
  "datetime"
16135
16215
  ]
16136
16216
  },
16137
- {
16138
- "path": "unit",
16139
- "valueType": "string"
16140
- },
16141
16217
  {
16142
16218
  "path": "min",
16143
16219
  "valueType": "number"
@@ -16149,19 +16225,6 @@ var CAP_STATE_LEAVES = Object.freeze({
16149
16225
  {
16150
16226
  "path": "step",
16151
16227
  "valueType": "number"
16152
- },
16153
- {
16154
- "path": "precision",
16155
- "valueType": "number"
16156
- },
16157
- {
16158
- "path": "format",
16159
- "valueType": "enum",
16160
- "enumValues": [
16161
- "date",
16162
- "time",
16163
- "datetime"
16164
- ]
16165
16228
  }
16166
16229
  ],
16167
16230
  "cover": [
@@ -16402,13 +16465,8 @@ var CAP_STATE_LEAVES = Object.freeze({
16402
16465
  "path": "value",
16403
16466
  "valueType": "string"
16404
16467
  }, {
16405
- "path": "format",
16406
- "valueType": "enum",
16407
- "enumValues": [
16408
- "date",
16409
- "time",
16410
- "datetime"
16411
- ]
16468
+ "path": "timestamp",
16469
+ "valueType": "boolean"
16412
16470
  }],
16413
16471
  "event-emitter": [
16414
16472
  {
@@ -16481,6 +16539,24 @@ var CAP_STATE_LEAVES = Object.freeze({
16481
16539
  "path": "detected",
16482
16540
  "valueType": "boolean"
16483
16541
  }],
16542
+ "group-active": [{
16543
+ "path": "active",
16544
+ "valueType": "boolean"
16545
+ }],
16546
+ "group-status": [
16547
+ {
16548
+ "path": "included",
16549
+ "valueType": "number"
16550
+ },
16551
+ {
16552
+ "path": "excluded",
16553
+ "valueType": "number"
16554
+ },
16555
+ {
16556
+ "path": "total",
16557
+ "valueType": "number"
16558
+ }
16559
+ ],
16484
16560
  "heating-valve": [{
16485
16561
  "path": "position",
16486
16562
  "valueType": "number"
@@ -16515,20 +16591,10 @@ var CAP_STATE_LEAVES = Object.freeze({
16515
16591
  "valueType": "number"
16516
16592
  }
16517
16593
  ],
16518
- "humidity-sensor": [
16519
- {
16520
- "path": "percent",
16521
- "valueType": "number"
16522
- },
16523
- {
16524
- "path": "unit",
16525
- "valueType": "string"
16526
- },
16527
- {
16528
- "path": "precision",
16529
- "valueType": "number"
16530
- }
16531
- ],
16594
+ "humidity-sensor": [{
16595
+ "path": "percent",
16596
+ "valueType": "number"
16597
+ }],
16532
16598
  "image": [{
16533
16599
  "path": "url",
16534
16600
  "valueType": "string"
@@ -16736,6 +16802,10 @@ var CAP_STATE_LEAVES = Object.freeze({
16736
16802
  ]
16737
16803
  }
16738
16804
  ],
16805
+ "meter": [{
16806
+ "path": "value",
16807
+ "valueType": "number"
16808
+ }],
16739
16809
  "motion": [
16740
16810
  {
16741
16811
  "path": "detected",
@@ -16867,20 +16937,10 @@ var CAP_STATE_LEAVES = Object.freeze({
16867
16937
  "valueType": "boolean"
16868
16938
  }
16869
16939
  ],
16870
- "numeric-sensor": [
16871
- {
16872
- "path": "value",
16873
- "valueType": "number"
16874
- },
16875
- {
16876
- "path": "unit",
16877
- "valueType": "string"
16878
- },
16879
- {
16880
- "path": "precision",
16881
- "valueType": "number"
16882
- }
16883
- ],
16940
+ "numeric-sensor": [{
16941
+ "path": "value",
16942
+ "valueType": "number"
16943
+ }],
16884
16944
  "pet-feeder": [
16885
16945
  {
16886
16946
  "path": "foodLevel",
@@ -16972,14 +17032,6 @@ var CAP_STATE_LEAVES = Object.freeze({
16972
17032
  {
16973
17033
  "path": "powerFactor",
16974
17034
  "valueType": "number"
16975
- },
16976
- {
16977
- "path": "unit",
16978
- "valueType": "string"
16979
- },
16980
- {
16981
- "path": "precision",
16982
- "valueType": "number"
16983
17035
  }
16984
17036
  ],
16985
17037
  "presence": [
@@ -17008,20 +17060,10 @@ var CAP_STATE_LEAVES = Object.freeze({
17008
17060
  "valueType": "number"
17009
17061
  }
17010
17062
  ],
17011
- "pressure-sensor": [
17012
- {
17013
- "path": "hpa",
17014
- "valueType": "number"
17015
- },
17016
- {
17017
- "path": "unit",
17018
- "valueType": "string"
17019
- },
17020
- {
17021
- "path": "precision",
17022
- "valueType": "number"
17023
- }
17024
- ],
17063
+ "pressure-sensor": [{
17064
+ "path": "hpa",
17065
+ "valueType": "number"
17066
+ }],
17025
17067
  "privacy-mask": [{
17026
17068
  "path": "enabled",
17027
17069
  "valueType": "boolean"
@@ -17332,20 +17374,10 @@ var CAP_STATE_LEAVES = Object.freeze({
17332
17374
  "path": "tampered",
17333
17375
  "valueType": "boolean"
17334
17376
  }],
17335
- "temperature-sensor": [
17336
- {
17337
- "path": "celsius",
17338
- "valueType": "number"
17339
- },
17340
- {
17341
- "path": "unit",
17342
- "valueType": "string"
17343
- },
17344
- {
17345
- "path": "precision",
17346
- "valueType": "number"
17347
- }
17348
- ],
17377
+ "temperature-sensor": [{
17378
+ "path": "celsius",
17379
+ "valueType": "number"
17380
+ }],
17349
17381
  "update": [
17350
17382
  {
17351
17383
  "path": "currentVersion",
@@ -17456,10 +17488,6 @@ var CAP_STATE_LEAVES = Object.freeze({
17456
17488
  "path": "temperature",
17457
17489
  "valueType": "number"
17458
17490
  },
17459
- {
17460
- "path": "temperatureUnit",
17461
- "valueType": "string"
17462
- },
17463
17491
  {
17464
17492
  "path": "humidity",
17465
17493
  "valueType": "number"
@@ -17468,18 +17496,10 @@ var CAP_STATE_LEAVES = Object.freeze({
17468
17496
  "path": "pressure",
17469
17497
  "valueType": "number"
17470
17498
  },
17471
- {
17472
- "path": "pressureUnit",
17473
- "valueType": "string"
17474
- },
17475
17499
  {
17476
17500
  "path": "windSpeed",
17477
17501
  "valueType": "number"
17478
17502
  },
17479
- {
17480
- "path": "windSpeedUnit",
17481
- "valueType": "string"
17482
- },
17483
17503
  {
17484
17504
  "path": "windBearing",
17485
17505
  "valueType": "number"
@@ -17541,7 +17561,7 @@ var BOOT_RECOVERY_BACKOFF_MS = [
17541
17561
  90 * 6e4
17542
17562
  ];
17543
17563
 
17544
- // ../types/dist/err-msg-BXKzRBwg.mjs
17564
+ // ../types/dist/err-msg-DIorGYeC.mjs
17545
17565
  var DeviceType = /* @__PURE__ */ (function(DeviceType2) {
17546
17566
  DeviceType2["Camera"] = "camera";
17547
17567
  DeviceType2["Hub"] = "hub";
@@ -17575,6 +17595,8 @@ var DeviceType = /* @__PURE__ */ (function(DeviceType2) {
17575
17595
  DeviceType2["Image"] = "image";
17576
17596
  DeviceType2["PetFeeder"] = "pet-feeder";
17577
17597
  DeviceType2["Dishwasher"] = "dishwasher";
17598
+ DeviceType2["Washer"] = "washer";
17599
+ DeviceType2["Dryer"] = "dryer";
17578
17600
  return DeviceType2;
17579
17601
  })({});
17580
17602
  var DeviceFeature = /* @__PURE__ */ (function(DeviceFeature2) {
@@ -17691,7 +17713,7 @@ var DeviceRole = /* @__PURE__ */ (function(DeviceRole2) {
17691
17713
  return DeviceRole2;
17692
17714
  })({});
17693
17715
 
17694
- // ../types/dist/composition-kEl9mevu.mjs
17716
+ // ../types/dist/composition-Bb8iwHEJ.mjs
17695
17717
  import { createHash } from "crypto";
17696
17718
  var DEFAULT_MAX_UNIT_BYTES = 16 * 1024 * 1024;
17697
17719
  var FFMPEG_RELEASE = "8.1.2-5";
@@ -17980,6 +18002,13 @@ var table = {
17980
18002
  apply: () => {
17981
18003
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
17982
18004
  }
18005
+ },
18006
+ schmitt: {
18007
+ minArgs: 3,
18008
+ maxArgs: 5,
18009
+ apply: () => {
18010
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
18011
+ }
17983
18012
  }
17984
18013
  };
17985
18014
  var EXPRESSION_BUILTINS = Object.freeze(Object.assign(/* @__PURE__ */ Object.create(null), table));
@@ -18358,14 +18387,224 @@ function validateExpressionSource(src) {
18358
18387
  }
18359
18388
  return null;
18360
18389
  }
18361
- var COMPOSER_ADDON_ID = "composer";
18362
- var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
18363
- var MAX_COMPOSITION_CODE_LENGTH = 2e4;
18390
+ var APPLIANCE_TEMPLATE_ID = "appliance";
18391
+ var APPLIANCE_KINDS = [
18392
+ "washer",
18393
+ "dryer",
18394
+ "dishwasher"
18395
+ ];
18396
+ var DEVICE_TYPE = {
18397
+ washer: DeviceType.Washer,
18398
+ dryer: DeviceType.Dryer,
18399
+ dishwasher: DeviceType.Dishwasher
18400
+ };
18401
+ var KWH_PER_WATT_MS = 1 / 36e8;
18402
+ var STATISTIC_STATS = [
18403
+ "min",
18404
+ "max",
18405
+ "mean",
18406
+ "sum",
18407
+ "count",
18408
+ "change"
18409
+ ];
18410
+ var MINUTE_MS = 6e4;
18411
+ var HOUR_MS = 60 * MINUTE_MS;
18412
+ var DAY_MS = 24 * HOUR_MS;
18413
+ var ROLLING_SPANS = [
18414
+ "1h",
18415
+ "24h",
18416
+ "2d",
18417
+ "7d",
18418
+ "30d",
18419
+ "custom"
18420
+ ];
18421
+ var CALENDAR_PERIODS = [
18422
+ "today",
18423
+ "yesterday",
18424
+ "this-week",
18425
+ "this-month"
18426
+ ];
18427
+ var RESET_PERIODS = [
18428
+ "never",
18429
+ "daily",
18430
+ "weekly",
18431
+ "monthly"
18432
+ ];
18433
+ var HISTORY_SLOW_MS = 5 * MINUTE_MS;
18434
+ var ROLLING_MS = {
18435
+ "1h": HOUR_MS,
18436
+ "24h": 24 * HOUR_MS,
18437
+ "2d": 2 * DAY_MS,
18438
+ "7d": 7 * DAY_MS,
18439
+ "30d": 30 * DAY_MS
18440
+ };
18441
+ var DEFAULT_HISTORY_RETENTION = {
18442
+ rawMs: 7 * DAY_MS,
18443
+ fiveMinuteMs: 30 * DAY_MS,
18444
+ hourMs: 365 * DAY_MS,
18445
+ dayMs: null
18446
+ };
18447
+ var rollingWindowObject = external_exports.object({
18448
+ kind: external_exports.literal("rolling"),
18449
+ span: external_exports.enum(ROLLING_SPANS),
18450
+ customMinutes: external_exports.number().int().min(5).optional()
18451
+ }).check((payload) => {
18452
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
18453
+ code: "custom",
18454
+ message: "a custom range needs a duration in minutes",
18455
+ path: ["customMinutes"],
18456
+ input: payload.value
18457
+ });
18458
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
18459
+ code: "custom",
18460
+ message: "only a custom range carries a duration",
18461
+ path: ["customMinutes"],
18462
+ input: payload.value
18463
+ });
18464
+ });
18465
+ var RollingWindowSchema = rollingWindowObject;
18466
+ var calendarWindowObject = external_exports.object({
18467
+ kind: external_exports.literal("calendar"),
18468
+ period: external_exports.enum(CALENDAR_PERIODS)
18469
+ });
18470
+ var StatisticWindowSchema = external_exports.discriminatedUnion("kind", [rollingWindowObject, calendarWindowObject]);
18364
18471
  var CompositionSourceRefSchema = external_exports.object({
18365
18472
  /** The owning addon; `stableId` is unique only within it. */
18366
18473
  addonId: external_exports.string().min(1),
18367
18474
  stableId: external_exports.string().min(1)
18368
18475
  });
18476
+ var GROUP_TEMPLATE_IDS = [
18477
+ "temperature",
18478
+ "humidity",
18479
+ "pressure",
18480
+ "illuminance",
18481
+ "power",
18482
+ "energy",
18483
+ "battery",
18484
+ "numeric",
18485
+ "motion",
18486
+ "contact",
18487
+ "leak",
18488
+ "smoke",
18489
+ "occupancy",
18490
+ "binary",
18491
+ "switch",
18492
+ "light",
18493
+ "fan",
18494
+ "cover",
18495
+ "valve",
18496
+ "lock",
18497
+ "media-player",
18498
+ "climate"
18499
+ ];
18500
+ var NUMERIC_AGGREGATES = [
18501
+ "mean",
18502
+ "median",
18503
+ "min",
18504
+ "max",
18505
+ "sum"
18506
+ ];
18507
+ var BINARY_AGGREGATES = ["any", "all"];
18508
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
18509
+ var AGGREGATE_REDUCERS = [
18510
+ "mean",
18511
+ "median",
18512
+ "min",
18513
+ "max",
18514
+ "sum",
18515
+ "any",
18516
+ "all"
18517
+ ];
18518
+ var GroupTemplateIdSchema = external_exports.enum(GROUP_TEMPLATE_IDS);
18519
+ var AggregateReducerSchema = external_exports.enum(AGGREGATE_REDUCERS);
18520
+ var ActiveCriterionSchema = external_exports.enum(ACTIVE_CRITERIA);
18521
+ var HelperMemberSchema = external_exports.object({
18522
+ source: CompositionSourceRefSchema,
18523
+ cap: external_exports.string().min(1),
18524
+ fieldPath: external_exports.string().min(1)
18525
+ });
18526
+ var GroupHelperSpecSchema = external_exports.object({
18527
+ kind: external_exports.literal("group"),
18528
+ templateId: GroupTemplateIdSchema,
18529
+ aggregate: AggregateReducerSchema,
18530
+ members: external_exports.array(HelperMemberSchema).min(1).max(64),
18531
+ /** Actuator groups only. Readings leave this unset. */
18532
+ active: ActiveCriterionSchema.optional()
18533
+ });
18534
+ var ApplianceHelperSpecSchema = external_exports.object({
18535
+ kind: external_exports.literal("appliance"),
18536
+ templateId: external_exports.literal(APPLIANCE_TEMPLATE_ID),
18537
+ appliance: external_exports.enum(APPLIANCE_KINDS),
18538
+ thresholdWatts: external_exports.number().positive(),
18539
+ startDwellMs: external_exports.number().int().nonnegative(),
18540
+ stopDwellMs: external_exports.number().int().nonnegative(),
18541
+ member: HelperMemberSchema
18542
+ });
18543
+ var statisticHelperObject = external_exports.object({
18544
+ kind: external_exports.literal("statistic"),
18545
+ stat: external_exports.enum(STATISTIC_STATS),
18546
+ window: StatisticWindowSchema,
18547
+ source: HelperMemberSchema
18548
+ });
18549
+ var INTEGRAL_OUTPUTS = ["energy", "meter"];
18550
+ var integralHelperObject = external_exports.object({
18551
+ kind: external_exports.literal("integral"),
18552
+ reset: external_exports.enum(RESET_PERIODS),
18553
+ output: external_exports.enum(INTEGRAL_OUTPUTS),
18554
+ source: HelperMemberSchema
18555
+ });
18556
+ var thresholdHelperObject = external_exports.object({
18557
+ kind: external_exports.literal("threshold"),
18558
+ source: HelperMemberSchema,
18559
+ high: external_exports.number(),
18560
+ low: external_exports.number(),
18561
+ onForMs: external_exports.number().int().nonnegative(),
18562
+ offForMs: external_exports.number().int().nonnegative()
18563
+ });
18564
+ var ARITHMETIC_OPS = [
18565
+ "sum",
18566
+ "difference",
18567
+ "ratio"
18568
+ ];
18569
+ var arithmeticHelperObject = external_exports.object({
18570
+ kind: external_exports.literal("arithmetic"),
18571
+ op: external_exports.enum(ARITHMETIC_OPS),
18572
+ inputs: external_exports.array(HelperMemberSchema).min(2).max(64)
18573
+ });
18574
+ var EXPRESSION_OUTPUTS = ["number", "boolean"];
18575
+ var expressionHelperObject = external_exports.object({
18576
+ kind: external_exports.literal("expression"),
18577
+ expr: external_exports.string().min(1),
18578
+ inputs: external_exports.array(external_exports.object({
18579
+ name: external_exports.string().min(1),
18580
+ member: HelperMemberSchema
18581
+ })).min(1).max(64),
18582
+ output: external_exports.enum(EXPRESSION_OUTPUTS)
18583
+ });
18584
+ var DERIVATIVE_UNITS = [
18585
+ "second",
18586
+ "minute",
18587
+ "hour"
18588
+ ];
18589
+ var derivativeHelperObject = external_exports.object({
18590
+ kind: external_exports.literal("derivative"),
18591
+ window: RollingWindowSchema,
18592
+ per: external_exports.enum(DERIVATIVE_UNITS),
18593
+ source: HelperMemberSchema
18594
+ });
18595
+ var HelperSpecSchema = external_exports.discriminatedUnion("kind", [
18596
+ GroupHelperSpecSchema,
18597
+ ApplianceHelperSpecSchema,
18598
+ statisticHelperObject,
18599
+ integralHelperObject,
18600
+ thresholdHelperObject,
18601
+ arithmeticHelperObject,
18602
+ expressionHelperObject,
18603
+ derivativeHelperObject
18604
+ ]);
18605
+ var COMPOSER_ADDON_ID = "composer";
18606
+ var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
18607
+ var MAX_COMPOSITION_CODE_LENGTH = 2e4;
18369
18608
  var CompositionFieldReadSchema = external_exports.object({
18370
18609
  source: CompositionSourceRefSchema,
18371
18610
  cap: external_exports.string().min(1),
@@ -18399,10 +18638,64 @@ var CompositionCodeSourceSchema = external_exports.object({
18399
18638
  kind: external_exports.literal("code"),
18400
18639
  code: external_exports.string().min(1).max(MAX_COMPOSITION_CODE_LENGTH)
18401
18640
  });
18641
+ var CompositionAggregateSourceSchema = external_exports.object({
18642
+ kind: external_exports.literal("aggregate"),
18643
+ reducer: external_exports.enum([
18644
+ "mean",
18645
+ "median",
18646
+ "min",
18647
+ "max",
18648
+ "sum",
18649
+ "any",
18650
+ "all"
18651
+ ]),
18652
+ reads: external_exports.array(CompositionFieldReadSchema).min(1).max(64),
18653
+ /**
18654
+ * Set when the reads are an enum state, not a yes/no: the listed states
18655
+ * count as active (a cover is `open`). A state outside the list is inactive;
18656
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
18657
+ */
18658
+ activeWhen: external_exports.array(external_exports.string().min(1)).min(1).optional(),
18659
+ /** `value` is the reading; the others are the member counts. */
18660
+ publish: external_exports.enum([
18661
+ "value",
18662
+ "included",
18663
+ "excluded",
18664
+ "total"
18665
+ ]),
18666
+ /** What a `value` publish does when nobody is included. Counts ignore this. */
18667
+ empty: external_exports.enum([
18668
+ "null",
18669
+ "omit",
18670
+ "offline"
18671
+ ])
18672
+ });
18673
+ var CompositionSeriesSourceSchema = external_exports.object({
18674
+ kind: external_exports.literal("series"),
18675
+ read: CompositionFieldReadSchema,
18676
+ /** `value` is the statistic or the integral. The others are the gap counts. */
18677
+ publish: external_exports.enum([
18678
+ "value",
18679
+ "included",
18680
+ "excluded",
18681
+ "total"
18682
+ ]),
18683
+ /**
18684
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
18685
+ * device unseeded until history answers, so a restart cannot publish 0.
18686
+ */
18687
+ empty: external_exports.enum([
18688
+ "null",
18689
+ "omit",
18690
+ "offline"
18691
+ ])
18692
+ });
18402
18693
  var CompositionFieldSourceSchema = external_exports.discriminatedUnion("kind", [
18403
18694
  CompositionFromSourceSchema,
18404
18695
  CompositionExpressionSourceSchema,
18405
- CompositionCodeSourceSchema
18696
+ CompositionCodeSourceSchema,
18697
+ CompositionAggregateSourceSchema,
18698
+ CompositionSeriesSourceSchema
18406
18699
  ]);
18407
18700
  var CompositionForwardCommandSchema = external_exports.object({
18408
18701
  kind: external_exports.literal("forward"),
@@ -18448,7 +18741,13 @@ var CompositionExistingTargetSchema = external_exports.object({
18448
18741
  var CompositionTargetSchema = external_exports.discriminatedUnion("kind", [CompositionNewTargetSchema, CompositionExistingTargetSchema]);
18449
18742
  var CompositionSchema = external_exports.object({
18450
18743
  target: CompositionTargetSchema,
18451
- features: external_exports.array(CompositionFeatureSchema).min(1).max(16)
18744
+ features: external_exports.array(CompositionFeatureSchema).min(1).max(16),
18745
+ /**
18746
+ * Present when the block is a helper template. Absent on a free
18747
+ * composition (the room example, device 4603). The editor reads this,
18748
+ * never the compiled features.
18749
+ */
18750
+ helper: HelperSpecSchema.optional()
18452
18751
  }).superRefine((composition, ctx) => {
18453
18752
  const seen = /* @__PURE__ */ new Set();
18454
18753
  composition.features.forEach((feature, index) => {
@@ -22728,7 +23027,22 @@ var BrokerProviderInfoSchema = external_exports.object({
22728
23027
  */
22729
23028
  interactiveConnectPath: external_exports.string().min(1).optional(),
22730
23029
  /** Relative hub path to disconnect the linked account (same popup pattern). */
22731
- interactiveDisconnectPath: external_exports.string().min(1).optional()
23030
+ interactiveDisconnectPath: external_exports.string().min(1).optional(),
23031
+ /**
23032
+ * The kind signs in through a server-held interactive session instead of
23033
+ * (or before) typed credentials. `basePath` is a hub-relative route set
23034
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
23035
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
23036
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
23037
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
23038
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
23039
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
23040
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
23041
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
23042
+ * offers it as the default path; the fields the session fills are
23043
+ * marked `filledBySignIn` in the kind's settings schema.
23044
+ */
23045
+ signIn: external_exports.object({ basePath: external_exports.string().min(1) }).optional()
22732
23046
  }))
22733
23047
  });
22734
23048
  var ListInputSchema = external_exports.object({
@@ -24062,7 +24376,12 @@ var CompositionProblemCodeSchema = external_exports.enum([
24062
24376
  "item-field-reserved",
24063
24377
  "target-missing",
24064
24378
  "target-unreadable",
24065
- "not-replaceable"
24379
+ "not-replaceable",
24380
+ "native-capability-replace",
24381
+ "mixed-quantity",
24382
+ "helper-mismatch",
24383
+ "member-constraint",
24384
+ "retention"
24066
24385
  ]);
24067
24386
  var CompositionProblemSchema = external_exports.object({
24068
24387
  code: CompositionProblemCodeSchema,
@@ -24079,7 +24398,8 @@ var CompositionUnavailableModeSchema = external_exports.enum([
24079
24398
  "null",
24080
24399
  "offline",
24081
24400
  "unknown",
24082
- "release"
24401
+ "release",
24402
+ "omit"
24083
24403
  ]);
24084
24404
  var CompositionFieldRoleSchema = external_exports.enum([
24085
24405
  "derived",
@@ -24282,8 +24602,748 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
24282
24602
  latchedAt: {
24283
24603
  kind: "fixed",
24284
24604
  result: ["number", "null"]
24605
+ },
24606
+ schmitt: {
24607
+ kind: "fixed",
24608
+ result: ["boolean", "null"]
24285
24609
  }
24286
24610
  });
24611
+ var NOW$2 = {
24612
+ fieldPath: "lastFetchedAt",
24613
+ expr: "now"
24614
+ };
24615
+ var CHANGED = {
24616
+ fieldPath: "lastChangedAt",
24617
+ expr: "now"
24618
+ };
24619
+ function numeric(input) {
24620
+ return {
24621
+ ...input,
24622
+ family: "numeric",
24623
+ deviceType: DeviceType.Sensor,
24624
+ memberDeviceType: DeviceType.Sensor,
24625
+ memberDeviceTypes: [DeviceType.Sensor],
24626
+ activeWhen: void 0,
24627
+ commandCaps: [],
24628
+ baseUnit: baseUnitOf(input.quantity),
24629
+ aggregates: NUMERIC_AGGREGATES,
24630
+ accept: [{
24631
+ cap: input.outputCap,
24632
+ fieldPath: input.outputField
24633
+ }]
24634
+ };
24635
+ }
24636
+ function binary(input) {
24637
+ return {
24638
+ ...input,
24639
+ family: "binary",
24640
+ deviceType: DeviceType.Sensor,
24641
+ memberDeviceType: DeviceType.Sensor,
24642
+ memberDeviceTypes: [DeviceType.Sensor],
24643
+ activeWhen: void 0,
24644
+ commandCaps: [],
24645
+ quantity: "none",
24646
+ baseUnit: void 0,
24647
+ aggregates: BINARY_AGGREGATES,
24648
+ empty: "offline"
24649
+ };
24650
+ }
24651
+ var GROUP_TEMPLATES = [
24652
+ numeric({
24653
+ id: "temperature",
24654
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 \xB0C.",
24655
+ role: DeviceRole.TemperatureSensor,
24656
+ outputCap: "temperature-sensor",
24657
+ outputField: "celsius",
24658
+ quantity: "temperature",
24659
+ defaultAggregate: "mean",
24660
+ empty: "null",
24661
+ companions: [NOW$2]
24662
+ }),
24663
+ numeric({
24664
+ id: "humidity",
24665
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
24666
+ role: DeviceRole.HumiditySensor,
24667
+ outputCap: "humidity-sensor",
24668
+ outputField: "percent",
24669
+ quantity: "humidity",
24670
+ defaultAggregate: "mean",
24671
+ empty: "null",
24672
+ companions: [NOW$2]
24673
+ }),
24674
+ numeric({
24675
+ id: "pressure",
24676
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
24677
+ role: DeviceRole.PressureSensor,
24678
+ outputCap: "pressure-sensor",
24679
+ outputField: "hpa",
24680
+ quantity: "pressure",
24681
+ defaultAggregate: "mean",
24682
+ empty: "null",
24683
+ companions: [NOW$2]
24684
+ }),
24685
+ numeric({
24686
+ id: "illuminance",
24687
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
24688
+ role: DeviceRole.AmbientLightSensor,
24689
+ outputCap: "ambient-light-sensor",
24690
+ outputField: "lux",
24691
+ quantity: "illuminance",
24692
+ defaultAggregate: "mean",
24693
+ empty: "null",
24694
+ companions: [NOW$2]
24695
+ }),
24696
+ numeric({
24697
+ id: "power",
24698
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
24699
+ role: DeviceRole.PowerSensor,
24700
+ outputCap: "power-meter",
24701
+ outputField: "watts",
24702
+ quantity: "power",
24703
+ defaultAggregate: "sum",
24704
+ empty: "omit",
24705
+ companions: [NOW$2]
24706
+ }),
24707
+ numeric({
24708
+ id: "energy",
24709
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
24710
+ role: DeviceRole.EnergySensor,
24711
+ outputCap: "power-meter",
24712
+ outputField: "kwhTotal",
24713
+ quantity: "energy",
24714
+ defaultAggregate: "sum",
24715
+ empty: "omit",
24716
+ companions: [NOW$2]
24717
+ }),
24718
+ numeric({
24719
+ id: "battery",
24720
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
24721
+ role: DeviceRole.BatterySensor,
24722
+ outputCap: "battery",
24723
+ outputField: "percentage",
24724
+ quantity: "percentage",
24725
+ defaultAggregate: "mean",
24726
+ empty: "null",
24727
+ companions: [
24728
+ {
24729
+ fieldPath: "charging",
24730
+ expr: '"unknown"'
24731
+ },
24732
+ {
24733
+ fieldPath: "sleeping",
24734
+ expr: "false"
24735
+ },
24736
+ {
24737
+ fieldPath: "lastUpdated",
24738
+ expr: "now"
24739
+ }
24740
+ ]
24741
+ }),
24742
+ numeric({
24743
+ id: "numeric",
24744
+ summary: "A numeric reading in the members\u2019 shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
24745
+ role: DeviceRole.NumericSensor,
24746
+ outputCap: "numeric-sensor",
24747
+ outputField: "value",
24748
+ quantity: "device",
24749
+ defaultAggregate: "mean",
24750
+ empty: "null",
24751
+ companions: [NOW$2]
24752
+ }),
24753
+ binary({
24754
+ id: "motion",
24755
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
24756
+ role: DeviceRole.MotionSensor,
24757
+ outputCap: "motion",
24758
+ outputField: "detected",
24759
+ defaultAggregate: "any",
24760
+ accept: [{
24761
+ cap: "motion",
24762
+ fieldPath: "detected"
24763
+ }],
24764
+ companions: [{
24765
+ fieldPath: "lastDetectedAt",
24766
+ expr: "null"
24767
+ }, {
24768
+ fieldPath: "autoClearAfterMs",
24769
+ expr: "null"
24770
+ }]
24771
+ }),
24772
+ binary({
24773
+ id: "contact",
24774
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
24775
+ role: DeviceRole.ContactSensor,
24776
+ outputCap: "contact",
24777
+ outputField: "entryOpen",
24778
+ defaultAggregate: "any",
24779
+ accept: [{
24780
+ cap: "contact",
24781
+ fieldPath: "entryOpen"
24782
+ }],
24783
+ companions: [CHANGED]
24784
+ }),
24785
+ binary({
24786
+ id: "leak",
24787
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
24788
+ role: DeviceRole.LeakSensor,
24789
+ outputCap: "flood",
24790
+ outputField: "flooded",
24791
+ defaultAggregate: "any",
24792
+ accept: [{
24793
+ cap: "flood",
24794
+ fieldPath: "flooded"
24795
+ }],
24796
+ companions: [CHANGED]
24797
+ }),
24798
+ binary({
24799
+ id: "smoke",
24800
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
24801
+ role: DeviceRole.SmokeSensor,
24802
+ outputCap: "smoke",
24803
+ outputField: "detected",
24804
+ defaultAggregate: "any",
24805
+ accept: [{
24806
+ cap: "smoke",
24807
+ fieldPath: "detected"
24808
+ }],
24809
+ companions: [CHANGED]
24810
+ }),
24811
+ binary({
24812
+ id: "occupancy",
24813
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
24814
+ role: DeviceRole.BinarySensor,
24815
+ outputCap: "binary",
24816
+ outputField: "on",
24817
+ defaultAggregate: "any",
24818
+ accept: [{
24819
+ cap: "motion",
24820
+ fieldPath: "detected"
24821
+ }, {
24822
+ cap: "binary",
24823
+ fieldPath: "on"
24824
+ }],
24825
+ companions: [CHANGED]
24826
+ }),
24827
+ binary({
24828
+ id: "binary",
24829
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
24830
+ role: DeviceRole.BinarySensor,
24831
+ outputCap: "binary",
24832
+ outputField: "on",
24833
+ defaultAggregate: "any",
24834
+ accept: [{
24835
+ cap: "binary",
24836
+ fieldPath: "on"
24837
+ }],
24838
+ companions: [CHANGED]
24839
+ }),
24840
+ actuator({
24841
+ id: "switch",
24842
+ summary: "On when at least one switch is on, or when all of them are. Offline and unknown members are left out of that decision, never read as off, and still receive the command.",
24843
+ deviceType: DeviceType.Switch,
24844
+ outputCap: "switch",
24845
+ outputField: "on",
24846
+ member: {
24847
+ cap: "switch",
24848
+ fieldPath: "on"
24849
+ },
24850
+ commandCaps: ["switch"]
24851
+ }),
24852
+ actuator({
24853
+ id: "light",
24854
+ summary: "On when at least one light is on, or when all of them are. Brightness and colour are offered only when every member has them. A command is not sent to a member that lacks it.",
24855
+ deviceType: DeviceType.Light,
24856
+ outputCap: "switch",
24857
+ outputField: "on",
24858
+ member: {
24859
+ cap: "switch",
24860
+ fieldPath: "on"
24861
+ },
24862
+ commandCaps: [
24863
+ "switch",
24864
+ "brightness",
24865
+ "color"
24866
+ ]
24867
+ }),
24868
+ actuator({
24869
+ id: "fan",
24870
+ summary: "On when at least one fan is on, or when all of them are. Speed, preset, direction and oscillation are offered only when every fan has them. A command is not sent to a fan that lacks it.",
24871
+ deviceType: DeviceType.Fan,
24872
+ outputCap: "switch",
24873
+ outputField: "on",
24874
+ member: {
24875
+ cap: "switch",
24876
+ fieldPath: "on"
24877
+ },
24878
+ commandCaps: ["switch", "fan-control"]
24879
+ }),
24880
+ actuator({
24881
+ id: "cover",
24882
+ summary: "Open when at least one cover is open or part-open, or only when all of them are. Position and tilt are offered only when every cover has them. A cover that reports nothing is left out, never read as closed.",
24883
+ deviceType: DeviceType.Cover,
24884
+ outputCap: "group-active",
24885
+ outputField: "active",
24886
+ member: {
24887
+ cap: "cover",
24888
+ fieldPath: "state"
24889
+ },
24890
+ activeWhen: [
24891
+ "open",
24892
+ "opening",
24893
+ "stopped"
24894
+ ],
24895
+ commandCaps: ["cover"]
24896
+ }),
24897
+ actuator({
24898
+ id: "valve",
24899
+ summary: "Open when at least one valve is open or part-open, or only when all of them are. Position is offered only when every valve has it. A valve that reports nothing is left out, never read as closed.",
24900
+ deviceType: DeviceType.Valve,
24901
+ outputCap: "group-active",
24902
+ outputField: "active",
24903
+ member: {
24904
+ cap: "valve",
24905
+ fieldPath: "state"
24906
+ },
24907
+ activeWhen: [
24908
+ "open",
24909
+ "opening",
24910
+ "stopped"
24911
+ ],
24912
+ commandCaps: ["valve"]
24913
+ }),
24914
+ actuator({
24915
+ id: "lock",
24916
+ summary: "Locked when at least one lock is locked, or only when all of them are. A jammed or moving lock is not locked. Locking is one tap; unlocking the group needs a confirmation every time, and nothing is sent without it.",
24917
+ deviceType: DeviceType.Lock,
24918
+ outputCap: "group-active",
24919
+ outputField: "active",
24920
+ member: {
24921
+ cap: "lock-control",
24922
+ fieldPath: "state"
24923
+ },
24924
+ activeWhen: ["locked"],
24925
+ commandCaps: ["lock-control"]
24926
+ }),
24927
+ actuator({
24928
+ id: "media-player",
24929
+ summary: "Playing when at least one player is playing, or only when all of them are. Volume is offered only when every player has it. A player that reports nothing is left out, never read as stopped.",
24930
+ deviceType: DeviceType.MediaPlayer,
24931
+ outputCap: "group-active",
24932
+ outputField: "active",
24933
+ member: {
24934
+ cap: "media-player",
24935
+ fieldPath: "state"
24936
+ },
24937
+ activeWhen: ["playing", "buffering"],
24938
+ commandCaps: ["media-player"]
24939
+ }),
24940
+ actuator({
24941
+ id: "climate",
24942
+ summary: "Running when at least one thermostat or air conditioner is not off, or only when all of them are. Target temperature and fan are offered only when every device has them. A device that reports nothing is left out, never read as off.",
24943
+ deviceType: DeviceType.Thermostat,
24944
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
24945
+ outputCap: "group-active",
24946
+ outputField: "active",
24947
+ member: {
24948
+ cap: "climate-control",
24949
+ fieldPath: "mode"
24950
+ },
24951
+ activeWhen: [
24952
+ "heat",
24953
+ "cool",
24954
+ "auto",
24955
+ "heat_cool",
24956
+ "fan_only",
24957
+ "dry"
24958
+ ],
24959
+ commandCaps: ["climate-control"]
24960
+ })
24961
+ ];
24962
+ function actuator(input) {
24963
+ return {
24964
+ id: input.id,
24965
+ summary: input.summary,
24966
+ deviceType: input.deviceType,
24967
+ outputCap: input.outputCap,
24968
+ outputField: input.outputField,
24969
+ commandCaps: input.commandCaps,
24970
+ family: "actuator",
24971
+ role: void 0,
24972
+ memberDeviceType: input.deviceType,
24973
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
24974
+ activeWhen: input.activeWhen,
24975
+ quantity: "none",
24976
+ baseUnit: void 0,
24977
+ aggregates: BINARY_AGGREGATES,
24978
+ defaultAggregate: "any",
24979
+ empty: "offline",
24980
+ accept: [input.member],
24981
+ companions: [CHANGED]
24982
+ };
24983
+ }
24984
+ var BY_ID = new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
24985
+ var COLOR_MODE_FEATURES = [
24986
+ DeviceFeature.LightColorRgb,
24987
+ DeviceFeature.LightColorHsv,
24988
+ DeviceFeature.LightColorMired
24989
+ ];
24990
+ var HISTORY_CATALOG = {
24991
+ "air-quality-sensor": {
24992
+ "co2Ppm": {
24993
+ kind: "gauge",
24994
+ unit: "ppm",
24995
+ deadband: 5
24996
+ },
24997
+ "vocPpb": {
24998
+ kind: "gauge",
24999
+ unit: "ppb",
25000
+ deadband: 5
25001
+ },
25002
+ "pm25": {
25003
+ kind: "gauge",
25004
+ unit: "\xB5g/m\xB3",
25005
+ deadband: 1
25006
+ },
25007
+ "pm10": {
25008
+ kind: "gauge",
25009
+ unit: "\xB5g/m\xB3",
25010
+ deadband: 1
25011
+ },
25012
+ "aqi": {
25013
+ kind: "gauge",
25014
+ unit: "count",
25015
+ deadband: 1
25016
+ }
25017
+ },
25018
+ "alarm-panel": { "state": {
25019
+ kind: "enum",
25020
+ values: [
25021
+ "disarmed",
25022
+ "armed_home",
25023
+ "armed_away",
25024
+ "armed_night",
25025
+ "armed_vacation",
25026
+ "armed_custom_bypass",
25027
+ "arming",
25028
+ "disarming",
25029
+ "pending",
25030
+ "triggered"
25031
+ ]
25032
+ } },
25033
+ "ambient-light-sensor": { "lux": {
25034
+ kind: "gauge",
25035
+ unit: "lx",
25036
+ deadbandPct: 10,
25037
+ minIntervalMs: 6e4
25038
+ } },
25039
+ "battery": {
25040
+ "percentage": {
25041
+ kind: "gauge",
25042
+ unit: "%"
25043
+ },
25044
+ "volts": {
25045
+ kind: "gauge",
25046
+ unit: "V"
25047
+ }
25048
+ },
25049
+ "binary": { "on": { kind: "boolean" } },
25050
+ "brightness": { "percentage": {
25051
+ kind: "gauge",
25052
+ unit: "%",
25053
+ minIntervalMs: 0
25054
+ } },
25055
+ "carbon-monoxide": { "detected": { kind: "boolean" } },
25056
+ "climate-control": {
25057
+ "currentTemp": {
25058
+ kind: "gauge",
25059
+ unit: "\xB0C",
25060
+ deadband: 0.1
25061
+ },
25062
+ "currentHumidity": {
25063
+ kind: "gauge",
25064
+ unit: "%",
25065
+ deadband: 0.5
25066
+ },
25067
+ "target": {
25068
+ kind: "gauge",
25069
+ unit: "\xB0C",
25070
+ minIntervalMs: 0
25071
+ },
25072
+ "targetHigh": {
25073
+ kind: "gauge",
25074
+ unit: "\xB0C",
25075
+ minIntervalMs: 0
25076
+ },
25077
+ "targetLow": {
25078
+ kind: "gauge",
25079
+ unit: "\xB0C",
25080
+ minIntervalMs: 0
25081
+ }
25082
+ },
25083
+ "connectivity": { "connected": { kind: "boolean" } },
25084
+ "contact": { "entryOpen": { kind: "boolean" } },
25085
+ "cover": { "position": {
25086
+ kind: "gauge",
25087
+ unit: "%",
25088
+ minIntervalMs: 0
25089
+ } },
25090
+ "device-status": { "online": { kind: "boolean" } },
25091
+ "dishwasher": {
25092
+ "progressPercent": {
25093
+ kind: "gauge",
25094
+ unit: "%",
25095
+ deadband: 2
25096
+ },
25097
+ "state": {
25098
+ kind: "enum",
25099
+ values: [
25100
+ "idle",
25101
+ "running",
25102
+ "paused",
25103
+ "finished",
25104
+ "error",
25105
+ "unavailable"
25106
+ ]
25107
+ },
25108
+ "operationState": {
25109
+ kind: "enum",
25110
+ values: [
25111
+ "Inactive",
25112
+ "Ready",
25113
+ "DelayedStart",
25114
+ "Run",
25115
+ "Pause",
25116
+ "ActionRequired",
25117
+ "Finished",
25118
+ "Error",
25119
+ "Aborting"
25120
+ ]
25121
+ },
25122
+ "remainingSeconds": {
25123
+ kind: "gauge",
25124
+ unit: "s",
25125
+ minIntervalMs: 6e4
25126
+ },
25127
+ "doorOpen": { kind: "boolean" },
25128
+ "powerOn": { kind: "boolean" }
25129
+ },
25130
+ "enum-sensor": { "value": {
25131
+ kind: "enum",
25132
+ skipWhenSet: "timestamp"
25133
+ } },
25134
+ "fan-control": {
25135
+ "percentage": {
25136
+ kind: "gauge",
25137
+ unit: "%",
25138
+ minIntervalMs: 0
25139
+ },
25140
+ "oscillating": { kind: "boolean" }
25141
+ },
25142
+ "flood": { "flooded": { kind: "boolean" } },
25143
+ "gas": { "detected": { kind: "boolean" } },
25144
+ "heating-valve": { "position": {
25145
+ kind: "gauge",
25146
+ unit: "%",
25147
+ deadband: 1
25148
+ } },
25149
+ "humidifier": {
25150
+ "currentHumidity": {
25151
+ kind: "gauge",
25152
+ unit: "%",
25153
+ deadband: 0.5
25154
+ },
25155
+ "on": { kind: "boolean" }
25156
+ },
25157
+ "humidity-sensor": { "percent": {
25158
+ kind: "gauge",
25159
+ unit: "%",
25160
+ deadband: 0.5
25161
+ } },
25162
+ "lawn-mower-control": { "batteryLevel": {
25163
+ kind: "gauge",
25164
+ unit: "%",
25165
+ deadband: 2
25166
+ } },
25167
+ "lock-control": { "state": {
25168
+ kind: "enum",
25169
+ values: [
25170
+ "locked",
25171
+ "unlocked",
25172
+ "locking",
25173
+ "unlocking",
25174
+ "jammed"
25175
+ ]
25176
+ } },
25177
+ "media-player": {
25178
+ "volumeLevel": {
25179
+ kind: "gauge",
25180
+ unit: "%",
25181
+ deadband: 1
25182
+ },
25183
+ "isMuted": { kind: "boolean" }
25184
+ },
25185
+ "meter": { "value": {
25186
+ kind: "counter",
25187
+ deadband: 1e-3,
25188
+ minIntervalMs: 6e4
25189
+ } },
25190
+ "motion": { "detected": {
25191
+ kind: "boolean",
25192
+ excludeDeviceTypes: [DeviceType.Camera]
25193
+ } },
25194
+ "network-link": {
25195
+ "signalPercent": {
25196
+ kind: "gauge",
25197
+ unit: "%",
25198
+ deadband: 3,
25199
+ minIntervalMs: 6e4
25200
+ },
25201
+ "rssiDbm": {
25202
+ kind: "gauge",
25203
+ unit: "dBm",
25204
+ deadband: 2,
25205
+ minIntervalMs: 6e4
25206
+ }
25207
+ },
25208
+ "numeric-sensor": { "value": {
25209
+ kind: "gauge",
25210
+ minIntervalMs: 3e4
25211
+ } },
25212
+ "pet-feeder": {
25213
+ "foodLevel": { kind: "gauge" },
25214
+ "food1": { kind: "gauge" },
25215
+ "food2": { kind: "gauge" },
25216
+ "batteryPower": {
25217
+ kind: "gauge",
25218
+ unit: "%",
25219
+ deadband: 2
25220
+ },
25221
+ "desiccantLeftDays": {
25222
+ kind: "gauge",
25223
+ unit: "s"
25224
+ }
25225
+ },
25226
+ "power-meter": {
25227
+ "watts": {
25228
+ kind: "gauge",
25229
+ unit: "W",
25230
+ deadband: 1,
25231
+ minIntervalMs: 3e4
25232
+ },
25233
+ "kwhTotal": {
25234
+ kind: "counter",
25235
+ unit: "kWh",
25236
+ deadband: 0.01,
25237
+ minIntervalMs: 6e4
25238
+ },
25239
+ "volts": {
25240
+ kind: "gauge",
25241
+ unit: "V",
25242
+ deadband: 1,
25243
+ minIntervalMs: 3e4
25244
+ },
25245
+ "amps": {
25246
+ kind: "gauge",
25247
+ unit: "A",
25248
+ deadband: 0.05,
25249
+ minIntervalMs: 3e4
25250
+ },
25251
+ "va": {
25252
+ kind: "gauge",
25253
+ unit: "VA",
25254
+ deadband: 1,
25255
+ minIntervalMs: 3e4
25256
+ },
25257
+ "powerFactor": {
25258
+ kind: "gauge",
25259
+ unit: "ratio",
25260
+ deadband: 0.01,
25261
+ minIntervalMs: 6e4
25262
+ }
25263
+ },
25264
+ "presence": { "batteryPercent": {
25265
+ kind: "gauge",
25266
+ unit: "%",
25267
+ deadband: 1
25268
+ } },
25269
+ "pressure-sensor": { "hpa": {
25270
+ kind: "gauge",
25271
+ unit: "hPa",
25272
+ deadband: 0.1
25273
+ } },
25274
+ "running-state": { "running": { kind: "boolean" } },
25275
+ "smoke": { "detected": { kind: "boolean" } },
25276
+ "stream-params": {
25277
+ "main.bitrate": {
25278
+ kind: "gauge",
25279
+ unit: "kbps"
25280
+ },
25281
+ "main.framerate": {
25282
+ kind: "gauge",
25283
+ unit: "fps"
25284
+ },
25285
+ "sub.bitrate": {
25286
+ kind: "gauge",
25287
+ unit: "kbps"
25288
+ },
25289
+ "sub.framerate": {
25290
+ kind: "gauge",
25291
+ unit: "fps"
25292
+ }
25293
+ },
25294
+ "switch": { "on": { kind: "boolean" } },
25295
+ "tamper": { "tampered": { kind: "boolean" } },
25296
+ "temperature-sensor": { "celsius": {
25297
+ kind: "gauge",
25298
+ unit: "\xB0C",
25299
+ deadband: 0.1
25300
+ } },
25301
+ "vacuum-control": { "batteryLevel": {
25302
+ kind: "gauge",
25303
+ unit: "%",
25304
+ deadband: 2
25305
+ } },
25306
+ "valve": { "position": {
25307
+ kind: "gauge",
25308
+ unit: "%",
25309
+ minIntervalMs: 0
25310
+ } },
25311
+ "vibration": { "detected": { kind: "boolean" } },
25312
+ "water-heater": {
25313
+ "currentTemp": {
25314
+ kind: "gauge",
25315
+ unit: "\xB0C",
25316
+ deadband: 0.5
25317
+ },
25318
+ "targetTemp": {
25319
+ kind: "gauge",
25320
+ unit: "\xB0C",
25321
+ minIntervalMs: 0
25322
+ }
25323
+ },
25324
+ "weather": {
25325
+ "temperature": {
25326
+ kind: "gauge",
25327
+ unit: "\xB0C",
25328
+ deadband: 0.2
25329
+ },
25330
+ "humidity": {
25331
+ kind: "gauge",
25332
+ unit: "%",
25333
+ deadband: 1
25334
+ },
25335
+ "pressure": {
25336
+ kind: "gauge",
25337
+ unit: "hPa",
25338
+ deadband: 0.5
25339
+ },
25340
+ "windSpeed": {
25341
+ kind: "gauge",
25342
+ unit: "m/s",
25343
+ deadband: 0.5
25344
+ }
25345
+ }
25346
+ };
24287
25347
  var PENDING_SELF = {
24288
25348
  addonId: COMPOSER_ADDON_ID,
24289
25349
  stableId: `${COMPOSED_DEVICE_STABLE_ID_PREFIX}(unsaved)`
@@ -26237,6 +27297,14 @@ var SourceInfoSchema = external_exports.object({
26237
27297
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
26238
27298
  * Used to detect rename when `id` changes. */
26239
27299
  uniqueId: external_exports.string().optional(),
27300
+ /** Quantity of a polymorphic reading, written once at adopt (D944). */
27301
+ quantity: ReadingQuantitySchema.optional(),
27302
+ /** Date / time / datetime shape of a string reading, written once at adopt. */
27303
+ dateTimeShape: external_exports.enum([
27304
+ "date",
27305
+ "time",
27306
+ "datetime"
27307
+ ]).optional(),
26240
27308
  /** Provider-specific extras that don't fit the structured slots.
26241
27309
  * Whitelist what goes here per provider — do NOT dump entire HA
26242
27310
  * attribute blobs (would explode the meta JSON column). */
@@ -47116,7 +48184,8 @@ var deviceManagerCapability = {
47116
48184
  "enum"
47117
48185
  ]),
47118
48186
  enumValues: external_exports.array(external_exports.string()).optional(),
47119
- item: external_exports.boolean().optional()
48187
+ item: external_exports.boolean().optional(),
48188
+ quantity: ReadingQuantitySchema.optional()
47120
48189
  })).readonly(),
47121
48190
  itemArray: external_exports.object({
47122
48191
  path: external_exports.string(),
@@ -51315,8 +52384,8 @@ var MaskPolygonShapeSchema = external_exports.object({
51315
52384
  });
51316
52385
  var MaskGridShapeSchema = external_exports.object({
51317
52386
  kind: external_exports.literal("grid"),
51318
- gridWidth: external_exports.number(),
51319
- gridHeight: external_exports.number(),
52387
+ gridWidth: external_exports.number().meta(readingMeta("none")),
52388
+ gridHeight: external_exports.number().meta(readingMeta("none")),
51320
52389
  cells: external_exports.array(external_exports.boolean())
51321
52390
  });
51322
52391
  var MaskLineShapeSchema = external_exports.object({
@@ -51369,6 +52438,8 @@ var NcSystemEventKindSchema = external_exports.enum([
51369
52438
  "detection-blind",
51370
52439
  "motion-noisy",
51371
52440
  "motion-calm",
52441
+ "package-llm-silent",
52442
+ "package-llm-answered",
51372
52443
  "recording-stalled",
51373
52444
  "recording-healthy",
51374
52445
  "recording-degraded",
@@ -52119,7 +53190,20 @@ var NcRuleInputSchema = external_exports.object({
52119
53190
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
52120
53191
  * path does not run Zod defaults.
52121
53192
  */
52122
- groupingSec: external_exports.number().int().min(5).max(60).optional()
53193
+ groupingSec: external_exports.number().int().min(5).max(60).optional(),
53194
+ /**
53195
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
53196
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
53197
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
53198
+ * same mark the Library writes, and records whose notification it was and
53199
+ * when. A channel with no buttons gets the same two choices as links.
53200
+ *
53201
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
53202
+ * cap path): absent and `false` both mean off, which is what every rule
53203
+ * authored before this field meant. An editor turns it off by writing
53204
+ * `false`, so it needs no `clear` key.
53205
+ */
53206
+ askVerdict: external_exports.boolean().optional()
52123
53207
  });
52124
53208
  var NcRulePatchSchema = NcRuleInputSchema.partial().extend({
52125
53209
  disabledTargetIds: external_exports.array(external_exports.string()).optional(),
@@ -62851,6 +63935,23 @@ var PackageVersionInfoSchema = external_exports.object({
62851
63935
  deprecated: external_exports.string().optional(),
62852
63936
  distTags: external_exports.array(external_exports.string()).readonly()
62853
63937
  });
63938
+ var PackageDocBodySchema = external_exports.discriminatedUnion("status", [
63939
+ external_exports.object({
63940
+ status: external_exports.literal("ok"),
63941
+ markdown: external_exports.string()
63942
+ }),
63943
+ external_exports.object({ status: external_exports.literal("missing") }),
63944
+ external_exports.object({
63945
+ status: external_exports.literal("error"),
63946
+ message: external_exports.string()
63947
+ })
63948
+ ]);
63949
+ var PackageDocsSchema = external_exports.object({
63950
+ name: external_exports.string(),
63951
+ version: external_exports.string(),
63952
+ readme: PackageDocBodySchema,
63953
+ changelog: PackageDocBodySchema
63954
+ });
62854
63955
  var SearchResultSchema = external_exports.object({
62855
63956
  name: external_exports.string(),
62856
63957
  version: external_exports.string(),
@@ -63180,6 +64281,15 @@ var addonsCapability = {
63180
64281
  auth: "admin"
63181
64282
  }),
63182
64283
  getVersions: method(external_exports.object({ name: external_exports.string() }), external_exports.array(PackageVersionInfoSchema).readonly()),
64284
+ /**
64285
+ * README and CHANGELOG for one registry package, read on the hub and
64286
+ * cached. `version` omitted resolves the `latest` dist-tag. The browser
64287
+ * never talks to the registry.
64288
+ */
64289
+ getPackageDocs: method(external_exports.object({
64290
+ name: external_exports.string().min(1),
64291
+ version: external_exports.string().min(1).optional()
64292
+ }), PackageDocsSchema, { auth: "admin" }),
63183
64293
  restartAddon: method(external_exports.object({ addonId: external_exports.string() }), RestartAddonResultSchema, {
63184
64294
  kind: "mutation",
63185
64295
  auth: "admin"
@@ -63275,27 +64385,17 @@ var addonsCapability = {
63275
64385
  };
63276
64386
  var AirQualitySensorStatusSchema = external_exports.object({
63277
64387
  /** Carbon dioxide concentration in ppm. */
63278
- co2Ppm: external_exports.number().min(0).optional(),
64388
+ co2Ppm: external_exports.number().min(0).optional().meta(readingMeta("concentration-volume")),
63279
64389
  /** Total volatile organic compounds in ppb. */
63280
- vocPpb: external_exports.number().min(0).optional(),
64390
+ vocPpb: external_exports.number().min(0).optional().meta(readingMeta("concentration-ppb")),
63281
64391
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
63282
- pm25: external_exports.number().min(0).optional(),
64392
+ pm25: external_exports.number().min(0).optional().meta(readingMeta("concentration-mass")),
63283
64393
  /** Particulate matter ≤ 10 μm in µg/m³. */
63284
- pm10: external_exports.number().min(0).optional(),
64394
+ pm10: external_exports.number().min(0).optional().meta(readingMeta("concentration-mass")),
63285
64395
  /** Composite AQI value (typically 0..500). */
63286
- aqi: external_exports.number().optional(),
64396
+ aqi: external_exports.number().optional().meta(readingMeta("index")),
63287
64397
  /** Ms epoch when the slice was last updated. */
63288
- lastFetchedAt: external_exports.number(),
63289
- /** Live display unit of the single metric this slice carries (e.g. HA
63290
- * `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
63291
- * upstream `sensor.*` entity surfaces ONE device_class, so one unit
63292
- * per slice is unambiguous. */
63293
- unit: external_exports.string().optional(),
63294
- /** Suggested decimal places for numeric display.
63295
- * Populated live from the upstream source when provided (e.g. HA
63296
- * `attributes.suggested_display_precision`). Falls back to
63297
- * auto-formatting when absent. */
63298
- precision: external_exports.number().int().min(0).max(10).optional()
64398
+ lastFetchedAt: external_exports.number()
63299
64399
  });
63300
64400
  var airQualitySensorCapability = {
63301
64401
  name: "air-quality-sensor",
@@ -63332,12 +64432,12 @@ var airQualitySensorCapability = {
63332
64432
  },
63333
64433
  pm25: {
63334
64434
  kind: "gauge",
63335
- unit: "ug/m3",
64435
+ unit: "\xB5g/m\xB3",
63336
64436
  deadband: 1
63337
64437
  },
63338
64438
  pm10: {
63339
64439
  kind: "gauge",
63340
- unit: "ug/m3",
64440
+ unit: "\xB5g/m\xB3",
63341
64441
  deadband: 1
63342
64442
  },
63343
64443
  aqi: {
@@ -63351,22 +64451,13 @@ var airQualitySensorCapability = {
63351
64451
  volatileStateFields: ["lastFetchedAt"]
63352
64452
  };
63353
64453
  var AmbientLightSensorStatusSchema = external_exports.object({
63354
- /** Current illuminance in lux (lx). */
63355
- lux: external_exports.number().min(0).meta({
63356
- unit: "lx",
64454
+ /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
64455
+ lux: external_exports.number().min(0).nullable().meta(readingMeta("illuminance", {
64456
+ precision: 0,
63357
64457
  label: "Illuminance"
63358
- }),
64458
+ })),
63359
64459
  /** Ms epoch when the slice was last updated. */
63360
- lastFetchedAt: external_exports.number(),
63361
- /** Live display unit from the upstream source (e.g. HA
63362
- * `attributes.unit_of_measurement`). The UI prefers this over the
63363
- * role's canonical unit. Absent → fall back to the canonical unit. */
63364
- unit: external_exports.string().optional(),
63365
- /** Suggested decimal places for numeric display.
63366
- * Populated live from the upstream source when provided (e.g. HA
63367
- * `attributes.suggested_display_precision`). Falls back to
63368
- * auto-formatting when absent. */
63369
- precision: external_exports.number().int().min(0).max(10).optional()
64460
+ lastFetchedAt: external_exports.number()
63370
64461
  });
63371
64462
  var ambientLightSensorCapability = {
63372
64463
  name: "ambient-light-sensor",
@@ -63398,12 +64489,7 @@ var ambientLightSensorCapability = {
63398
64489
  } } },
63399
64490
  /** Clock fields: written, but excluded from the compare that decides
63400
64491
  * whether persisting is worth a SQLite commit. */
63401
- volatileStateFields: ["lastFetchedAt"],
63402
- customize: {
63403
- version: 1,
63404
- advanced: "derive",
63405
- targets: []
63406
- }
64492
+ volatileStateFields: ["lastFetchedAt"]
63407
64493
  };
63408
64494
  var AudioClassSummarySchema = external_exports.object({
63409
64495
  className: external_exports.string(),
@@ -63584,10 +64670,7 @@ var BatteryStatusSchema = external_exports.object({
63584
64670
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
63585
64671
  * declines to band a non-finite reading, which is the correct shape.
63586
64672
  */
63587
- percentage: external_exports.number().min(0).max(100).nullable().meta({
63588
- unit: "%",
63589
- label: "Charge"
63590
- }),
64673
+ percentage: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
63591
64674
  /**
63592
64675
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
63593
64676
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -63614,7 +64697,14 @@ var BatteryStatusSchema = external_exports.object({
63614
64697
  */
63615
64698
  sleeping: external_exports.boolean().meta({ label: "Sleeping" }),
63616
64699
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
63617
- lastUpdated: external_exports.number(),
64700
+ lastUpdated: external_exports.number().meta(readingMeta("none")),
64701
+ /**
64702
+ * Battery voltage in volts, for a cell the firmware reports as voltage
64703
+ * rather than a percentage (Ecowitt capacitor packs). Absent on cameras
64704
+ * that only report charge. A second reading on this cap, not a second
64705
+ * `numeric-sensor` on the same device.
64706
+ */
64707
+ volts: external_exports.number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
63618
64708
  /**
63619
64709
  * Ms epoch of the last time the device PROVED it was reachable — a
63620
64710
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -63661,11 +64751,11 @@ var BATTERY_DEVICE_TYPES = [
63661
64751
  DeviceType.Switch,
63662
64752
  DeviceType.PetFeeder,
63663
64753
  DeviceType.Container,
63664
- DeviceType.Thermostat
64754
+ DeviceType.Thermostat,
64755
+ DeviceType.EventEmitter
63665
64756
  ];
63666
64757
  var batteryCustomize = {
63667
64758
  version: 1,
63668
- advanced: "derive",
63669
64759
  targets: [{
63670
64760
  id: "percentage",
63671
64761
  cardinality: "scalar",
@@ -63674,7 +64764,7 @@ var batteryCustomize = {
63674
64764
  stateField: "percentage"
63675
64765
  },
63676
64766
  deviceTypes: BATTERY_DEVICE_TYPES,
63677
- apply: "add-or-replace",
64767
+ apply: "add",
63678
64768
  path: "percentage",
63679
64769
  sources: [{
63680
64770
  kind: "field",
@@ -63797,10 +64887,16 @@ var batteryCapability = {
63797
64887
  /**
63798
64888
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
63799
64889
  */
63800
- history: { fields: { percentage: {
63801
- kind: "gauge",
63802
- unit: "%"
63803
- } } },
64890
+ history: { fields: {
64891
+ percentage: {
64892
+ kind: "gauge",
64893
+ unit: "%"
64894
+ },
64895
+ volts: {
64896
+ kind: "gauge",
64897
+ unit: "V"
64898
+ }
64899
+ } },
63804
64900
  customize: batteryCustomize,
63805
64901
  /** Clock fields: written, but excluded from the compare that decides
63806
64902
  * whether persisting is worth a SQLite commit. */
@@ -63836,16 +64932,11 @@ var binaryCapability = {
63836
64932
  history: { fields: { on: { kind: "boolean" } } },
63837
64933
  /** Clock fields: written, but excluded from the compare that decides
63838
64934
  * whether persisting is worth a SQLite commit. */
63839
- volatileStateFields: ["lastChangedAt"],
63840
- customize: {
63841
- version: 1,
63842
- advanced: "derive",
63843
- targets: []
63844
- }
64935
+ volatileStateFields: ["lastChangedAt"]
63845
64936
  };
63846
64937
  var BrightnessStatusSchema = external_exports.object({
63847
64938
  /** Current level as 0..100 inclusive. Firmware-reported. */
63848
- percentage: external_exports.number().min(0).max(100),
64939
+ percentage: external_exports.number().min(0).max(100).meta(readingMeta("percentage")),
63849
64940
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
63850
64941
  lastChangedAt: external_exports.number()
63851
64942
  });
@@ -64223,21 +65314,21 @@ var ClimateControlStatusSchema = external_exports.object({
64223
65314
  /** Single setpoint in Celsius. Used by single-target modes
64224
65315
  * (heat / cool / dry). Null when the device is in a range mode
64225
65316
  * (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
64226
- target: external_exports.number().nullable(),
65317
+ target: external_exports.number().nullable().meta(readingMeta("temperature")),
64227
65318
  /** Upper bound of the dual setpoint in Celsius. Populated only
64228
65319
  * in `heat_cool` mode. */
64229
- targetHigh: external_exports.number().nullable(),
65320
+ targetHigh: external_exports.number().nullable().meta(readingMeta("temperature")),
64230
65321
  /** Lower bound of the dual setpoint in Celsius. Populated only
64231
65322
  * in `heat_cool` mode. */
64232
- targetLow: external_exports.number().nullable(),
65323
+ targetLow: external_exports.number().nullable().meta(readingMeta("temperature")),
64233
65324
  /** Target relative humidity (0..100). Null when the device has no
64234
65325
  * humidity control. */
64235
- targetHumidity: external_exports.number().min(0).max(100).nullable(),
65326
+ targetHumidity: external_exports.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
64236
65327
  /** Current measured temperature in Celsius. Read-only — pushed by
64237
65328
  * the device's internal sensor. */
64238
- currentTemp: external_exports.number().nullable(),
65329
+ currentTemp: external_exports.number().nullable().meta(readingMeta("temperature")),
64239
65330
  /** Current measured relative humidity (0..100). Read-only. */
64240
- currentHumidity: external_exports.number().min(0).max(100).nullable(),
65331
+ currentHumidity: external_exports.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
64241
65332
  /** Vertical louver swing on/off. Null when the device has no vertical
64242
65333
  * swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
64243
65334
  swingVertical: external_exports.boolean().nullable(),
@@ -64245,11 +65336,11 @@ var ClimateControlStatusSchema = external_exports.object({
64245
65336
  * horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
64246
65337
  swingHorizontal: external_exports.boolean().nullable(),
64247
65338
  /** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
64248
- minTemp: external_exports.number().nullable().optional(),
65339
+ minTemp: external_exports.number().nullable().optional().meta(readingMeta("temperature")),
64249
65340
  /** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
64250
- maxTemp: external_exports.number().nullable().optional(),
65341
+ maxTemp: external_exports.number().nullable().optional().meta(readingMeta("temperature")),
64251
65342
  /** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
64252
- tempStep: external_exports.number().positive().nullable().optional(),
65343
+ tempStep: external_exports.number().positive().nullable().optional().meta(readingMeta("temperature")),
64253
65344
  /** Ms epoch when the slice was last updated (push or command). */
64254
65345
  lastFetchedAt: external_exports.number()
64255
65346
  });
@@ -64367,17 +65458,17 @@ var climateControlCapability = {
64367
65458
  } }
64368
65459
  };
64369
65460
  var RgbTripletSchema = external_exports.object({
64370
- r: external_exports.number().int().min(0).max(255),
64371
- g: external_exports.number().int().min(0).max(255),
64372
- b: external_exports.number().int().min(0).max(255)
65461
+ r: external_exports.number().int().min(0).max(255).meta(readingMeta("none")),
65462
+ g: external_exports.number().int().min(0).max(255).meta(readingMeta("none")),
65463
+ b: external_exports.number().int().min(0).max(255).meta(readingMeta("none"))
64373
65464
  });
64374
65465
  var HsvTripletSchema = external_exports.object({
64375
65466
  /** Hue in degrees, 0..360. */
64376
- h: external_exports.number().min(0).max(360),
65467
+ h: external_exports.number().min(0).max(360).meta(readingMeta("none")),
64377
65468
  /** Saturation as 0..100 inclusive. */
64378
- s: external_exports.number().min(0).max(100),
65469
+ s: external_exports.number().min(0).max(100).meta(readingMeta("none")),
64379
65470
  /** Value/brightness as 0..100 inclusive. */
64380
- v: external_exports.number().min(0).max(100)
65471
+ v: external_exports.number().min(0).max(100).meta(readingMeta("none"))
64381
65472
  });
64382
65473
  var ColorInputSchema = external_exports.discriminatedUnion("mode", [
64383
65474
  external_exports.object({
@@ -64406,7 +65497,7 @@ var ColorStatusSchema = external_exports.object({
64406
65497
  /** Populated when `mode === 'hsv'`. */
64407
65498
  hsv: HsvTripletSchema.optional(),
64408
65499
  /** Populated when `mode === 'mired'`. */
64409
- mireds: external_exports.number().int().optional(),
65500
+ mireds: external_exports.number().int().optional().meta(readingMeta("colour-temperature")),
64410
65501
  /** Ms epoch of the last operator-driven change. */
64411
65502
  lastChangedAt: external_exports.number()
64412
65503
  });
@@ -64558,14 +65649,10 @@ var ConsumableLevelSchema = external_exports.enum([
64558
65649
  "empty",
64559
65650
  "full"
64560
65651
  ]);
64561
- var ConsumableRemainingUnitSchema = external_exports.enum([
64562
- "days",
64563
- "hours",
64564
- "cycles"
64565
- ]);
65652
+ var ConsumableRemainingKindSchema = external_exports.enum(["duration", "count"]);
64566
65653
  var ConsumableRemainingSchema = external_exports.object({
64567
- value: external_exports.number().min(0).nullable(),
64568
- unit: ConsumableRemainingUnitSchema
65654
+ value: external_exports.number().min(0).nullable().meta(readingMeta("device")),
65655
+ kind: ConsumableRemainingKindSchema
64569
65656
  });
64570
65657
  var ConsumableItemSchema = external_exports.object({
64571
65658
  /** Stable id, e.g. 'main-brush'. */
@@ -64573,7 +65660,7 @@ var ConsumableItemSchema = external_exports.object({
64573
65660
  /** Display name. */
64574
65661
  label: external_exports.string().min(1),
64575
65662
  /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
64576
- level: external_exports.number().min(0).max(100).nullable(),
65663
+ level: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64577
65664
  /** The provider's discrete verdict when known (binary mode). */
64578
65665
  status: ConsumableStatusSchema.nullable(),
64579
65666
  /** What the item is — decides whether low or full is bad. Absent = `wear`. */
@@ -64631,8 +65718,8 @@ var consumablesCustomize = {
64631
65718
  transforms: [{ kind: "identity" }]
64632
65719
  }],
64633
65720
  literals: [{
64634
- path: "remaining.unit",
64635
- values: [...ConsumableRemainingUnitSchema.options]
65721
+ path: "remaining.kind",
65722
+ values: [...ConsumableRemainingKindSchema.options]
64636
65723
  }]
64637
65724
  },
64638
65725
  {
@@ -64762,7 +65849,6 @@ var consumablesCapability = {
64762
65849
  },
64763
65850
  "remaining.value": {
64764
65851
  kind: "gauge",
64765
- unitFrom: "remaining.unit",
64766
65852
  deadband: 1,
64767
65853
  displayName: "Remaining"
64768
65854
  }
@@ -64816,39 +65902,17 @@ var ControlStatusSchema = external_exports.object({
64816
65902
  /** Current value. Numeric kind → number; select/text/datetime → string.
64817
65903
  * Datetime values are ISO 8601 strings (full timestamp, date-only,
64818
65904
  * or time-only — HA accepts all three forms). */
64819
- value: external_exports.union([external_exports.number(), external_exports.string()]),
65905
+ value: external_exports.union([external_exports.number().meta(readingMeta("device")), external_exports.string()]),
64820
65906
  /** Acceptable values when `kind === 'select'`. Empty for other kinds. */
64821
65907
  options: external_exports.array(external_exports.string()),
64822
65908
  /** Ms epoch when the slice was last updated. */
64823
65909
  lastChangedAt: external_exports.number(),
64824
- /** Display unit-of-measurement (e.g. '°C', '%', 'lx').
64825
- * Populated live from HA `attributes.unit_of_measurement` on each push.
64826
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
64827
- unit: external_exports.string().optional(),
64828
- /** Minimum allowed value. Populated live from HA `attributes.min`.
64829
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
64830
- min: external_exports.number().optional(),
64831
- /** Maximum allowed value. Populated live from HA `attributes.max`.
64832
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
64833
- max: external_exports.number().optional(),
64834
- /** Step increment. Populated live from HA `attributes.step`.
64835
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
64836
- step: external_exports.number().optional(),
64837
- /** Suggested decimal places for numeric display. Populated live from HA
64838
- * `attributes.suggested_display_precision`, or derived from `step` when the
64839
- * HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
64840
- * other kinds. Falls back to auto-formatting when absent. */
64841
- precision: external_exports.number().int().min(0).max(10).optional(),
64842
- /** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
64843
- * 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
64844
- * (UI defaults to 'datetime'). Derived live from the device's HA domain
64845
- * (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
64846
- * `has_date`/`has_time` attributes on each push. */
64847
- format: external_exports.enum([
64848
- "date",
64849
- "time",
64850
- "datetime"
64851
- ]).optional()
65910
+ /** Minimum allowed value, in the device quantity's base unit. */
65911
+ min: external_exports.number().optional().meta(readingMeta("device")),
65912
+ /** Maximum allowed value, in the device quantity's base unit. */
65913
+ max: external_exports.number().optional().meta(readingMeta("device")),
65914
+ /** Step increment, in the device quantity's base unit. */
65915
+ step: external_exports.number().optional().meta(readingMeta("device"))
64852
65916
  });
64853
65917
  var ControlSetValueInputSchema = external_exports.discriminatedUnion("kind", [
64854
65918
  external_exports.object({
@@ -64915,9 +65979,9 @@ var CoverStatusSchema = external_exports.object({
64915
65979
  state: CoverStateSchema,
64916
65980
  /** 0 = fully closed, 100 = fully open. Null when the device has
64917
65981
  * no intermediate position surface. */
64918
- position: external_exports.number().min(0).max(100).nullable(),
65982
+ position: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64919
65983
  /** 0 = closed slats, 100 = open slats. Null when no tilt support. */
64920
- tiltPosition: external_exports.number().min(0).max(100).nullable(),
65984
+ tiltPosition: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64921
65985
  /** Ms epoch when the slice was last updated. */
64922
65986
  lastChangedAt: external_exports.number()
64923
65987
  });
@@ -64997,9 +66061,9 @@ var NormalizedRangeSchema$1 = external_exports.object({
64997
66061
  var DayNightStatusSchema = external_exports.object({
64998
66062
  mode: DayNightModeSchema,
64999
66063
  /** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
65000
- sensitivity: external_exports.number().optional(),
66064
+ sensitivity: external_exports.number().optional().meta(readingMeta("none")),
65001
66065
  /** Delay before the IR-cut filter flips, in seconds. */
65002
- switchDelaySec: external_exports.number().optional(),
66066
+ switchDelaySec: external_exports.number().optional().meta(readingMeta("duration")),
65003
66067
  lastFetchedAt: external_exports.number()
65004
66068
  });
65005
66069
  var DayNightOptionsSchema = external_exports.object({
@@ -65167,11 +66231,11 @@ var DishwasherStatusSchema = external_exports.object({
65167
66231
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
65168
66232
  availablePrograms: external_exports.array(external_exports.string()),
65169
66233
  /** Seconds remaining on the active cycle, or null when not running / not known. */
65170
- remainingSeconds: external_exports.number().int().nonnegative().nullable(),
66234
+ remainingSeconds: external_exports.number().int().nonnegative().nullable().meta(readingMeta("duration")),
65171
66235
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
65172
- delayedStartSeconds: external_exports.number().int().nonnegative().nullable(),
66236
+ delayedStartSeconds: external_exports.number().int().nonnegative().nullable().meta(readingMeta("duration")),
65173
66237
  /** Cycle completion 0..100, or null when not applicable. */
65174
- progressPercent: external_exports.number().min(0).max(100).nullable(),
66238
+ progressPercent: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65175
66239
  /** True when the door is reported open; null when the door state is not known. */
65176
66240
  doorOpen: external_exports.boolean().nullable(),
65177
66241
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -65195,7 +66259,7 @@ var DishwasherStatusSchema = external_exports.object({
65195
66259
  /** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
65196
66260
  machineCareDue: external_exports.boolean().nullable(),
65197
66261
  /** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
65198
- machineCareRemainingRuns: external_exports.number().int().nonnegative().nullable(),
66262
+ machineCareRemainingRuns: external_exports.number().int().nonnegative().nullable().meta(readingMeta("count")),
65199
66263
  /** Option states: null when the appliance does not expose the option or has not said. */
65200
66264
  halfLoad: external_exports.boolean().nullable(),
65201
66265
  hygienePlus: external_exports.boolean().nullable(),
@@ -65210,7 +66274,7 @@ var DishwasherStatusSchema = external_exports.object({
65210
66274
  /** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
65211
66275
  activeEvents: external_exports.array(external_exports.string()),
65212
66276
  /** Numeric error code when the appliance reports one; null otherwise. */
65213
- errorCode: external_exports.number().nullable(),
66277
+ errorCode: external_exports.number().nullable().meta(readingMeta("none")),
65214
66278
  /** Name of the raised alert-level event while the appliance is in error; null otherwise. */
65215
66279
  errorLabel: external_exports.string().nullable(),
65216
66280
  /** Ms epoch of the last value received from the appliance; 0 = never. */
@@ -65417,6 +66481,7 @@ var doorbellCustomize = {
65417
66481
  applyAuthority: { kind: "composition-claim" },
65418
66482
  eventName: "onPressed",
65419
66483
  edges: ["rising"],
66484
+ defaultEdge: "rising",
65420
66485
  timestampPath: "lastPressedAt",
65421
66486
  counterPath: "pressCountSinceStart",
65422
66487
  highWater: "composer-advance",
@@ -65435,7 +66500,7 @@ var DoorbellStatusSchema = external_exports.object({
65435
66500
  /** Ms epoch of the last press. null = never observed since this provider started. */
65436
66501
  lastPressedAt: external_exports.number().nullable(),
65437
66502
  /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
65438
- pressCountSinceStart: external_exports.number()
66503
+ pressCountSinceStart: external_exports.number().meta(readingMeta("count"))
65439
66504
  });
65440
66505
  var DoorbellPressEventSchema = external_exports.object({
65441
66506
  deviceId: external_exports.number(),
@@ -65494,12 +66559,11 @@ var EnumSensorDateTimeFormatSchema = external_exports.enum([
65494
66559
  var EnumSensorStatusSchema = external_exports.object({
65495
66560
  value: external_exports.string(),
65496
66561
  /**
65497
- * Set for `DateTimeSensor`-role sensors so the UI renders the ISO `value`
65498
- * as a locale date/time/datetime; absent for plain enum sensors. HA
65499
- * `device_class=timestamp` → `'datetime'`, `device_class=date` → `'date'`,
65500
- * a time-only sensor → `'time'`.
66562
+ * Set when `value` is a timestamp rather than an enum state, so history
66563
+ * does not learn ISO strings as states. The display shape (date / time /
66564
+ * datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
65501
66565
  */
65502
- format: EnumSensorDateTimeFormatSchema.optional(),
66566
+ timestamp: external_exports.boolean().optional(),
65503
66567
  /** Ms epoch when the slice was last updated. */
65504
66568
  lastFetchedAt: external_exports.number()
65505
66569
  });
@@ -65526,11 +66590,11 @@ var enumSensorCapability = {
65526
66590
  * History (D850): the value as an `enum` series (an appliance's program or
65527
66591
  * operation state, an HVAC action). The option set is per device, so the
65528
66592
  * value list is LEARNED as values are first seen (bounded). A sensor with a
65529
- * `format` carries a timestamp, not a state, and is not recorded.
66593
+ * `timestamp` carries a clock, not a state, and is not recorded.
65530
66594
  */
65531
66595
  history: { fields: { value: {
65532
66596
  kind: "enum",
65533
- skipWhenSet: "format"
66597
+ skipWhenSet: "timestamp"
65534
66598
  } } },
65535
66599
  /** Clock fields: written, but excluded from the compare that decides
65536
66600
  * whether persisting is worth a SQLite commit. */
@@ -65540,13 +66604,13 @@ var EventFireSchema = external_exports.object({
65540
66604
  deviceId: external_exports.number(),
65541
66605
  eventType: external_exports.string(),
65542
66606
  data: external_exports.record(external_exports.string(), external_exports.unknown()).nullable(),
65543
- timestamp: external_exports.number(),
65544
- seq: external_exports.number()
66607
+ timestamp: external_exports.number().meta(readingMeta("none")),
66608
+ seq: external_exports.number().meta(readingMeta("count"))
65545
66609
  });
65546
66610
  var EventEmitterStatusSchema = external_exports.object({
65547
66611
  eventTypes: external_exports.array(external_exports.string()),
65548
66612
  lastEvent: EventFireSchema.nullable(),
65549
- eventCountSinceStart: external_exports.number()
66613
+ eventCountSinceStart: external_exports.number().meta(readingMeta("count"))
65550
66614
  });
65551
66615
  var eventEmitterCapability = {
65552
66616
  name: "event-emitter",
@@ -65936,10 +67000,10 @@ var FanDirectionSchema = external_exports.enum(["forward", "reverse"]);
65936
67000
  var FanControlStatusSchema = external_exports.object({
65937
67001
  /** Active speed as 0..100 inclusive. Null when the device has no
65938
67002
  * speed surface (single-speed fan). */
65939
- percentage: external_exports.number().min(0).max(100).nullable(),
67003
+ percentage: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65940
67004
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
65941
67005
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
65942
- percentageStep: external_exports.number().positive().optional(),
67006
+ percentageStep: external_exports.number().positive().optional().meta(readingMeta("percentage")),
65943
67007
  /** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
65944
67008
  * — empty string when no preset is active or supported. */
65945
67009
  preset: external_exports.string(),
@@ -66036,7 +67100,7 @@ var FeatureProbeStatusSchema = external_exports.object({
66036
67100
  /** Camera/firmware model string. `null` when the firmware doesn't expose it. */
66037
67101
  model: external_exports.string().nullable(),
66038
67102
  /** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
66039
- channelCount: external_exports.number().nullable(),
67103
+ channelCount: external_exports.number().nullable().meta(readingMeta("count")),
66040
67104
  /**
66041
67105
  * Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
66042
67106
  * completes — drivers' `getAccessoryChildren()` should treat zero as
@@ -66147,9 +67211,138 @@ var gasCapability = {
66147
67211
  * whether persisting is worth a SQLite commit. */
66148
67212
  volatileStateFields: ["lastChangedAt"]
66149
67213
  };
67214
+ var GroupCommandResultSchema = external_exports.object({
67215
+ deviceId: external_exports.number().int().nonnegative(),
67216
+ cap: external_exports.string().min(1),
67217
+ method: external_exports.string().min(1),
67218
+ ok: external_exports.boolean(),
67219
+ error: external_exports.string().optional(),
67220
+ /** Ms epoch of the attempt. */
67221
+ at: external_exports.number()
67222
+ });
67223
+ var GroupCommandsSchema = external_exports.object({
67224
+ /** One row per member that has been commanded. A later command replaces that member's row. */
67225
+ results: external_exports.array(GroupCommandResultSchema)
67226
+ });
67227
+ var groupCommandsCapability = {
67228
+ name: "group-commands",
67229
+ scope: "device",
67230
+ deviceNative: true,
67231
+ mode: "singleton",
67232
+ deviceTypes: [
67233
+ DeviceType.Switch,
67234
+ DeviceType.Light,
67235
+ DeviceType.Fan,
67236
+ DeviceType.Cover,
67237
+ DeviceType.Valve,
67238
+ DeviceType.Lock,
67239
+ DeviceType.MediaPlayer,
67240
+ DeviceType.Thermostat,
67241
+ DeviceType.Climate
67242
+ ],
67243
+ methods: {},
67244
+ status: {
67245
+ schema: GroupCommandsSchema,
67246
+ kind: "push"
67247
+ },
67248
+ runtimeState: GroupCommandsSchema,
67249
+ /**
67250
+ * Runtime-state durability: **session** — the last attempt. A restored
67251
+ * failure would outlive the command that caused it.
67252
+ *
67253
+ * See `RuntimeStateDurability`. Enforced by
67254
+ * `scripts/check-runtime-state-durability.ts`.
67255
+ */
67256
+ durability: "session",
67257
+ history: "none"
67258
+ };
67259
+ var GroupActiveSchema = external_exports.object({
67260
+ active: external_exports.boolean().meta({ label: "Active" }),
67261
+ /** Ms epoch when the slice was last updated. */
67262
+ lastChangedAt: external_exports.number()
67263
+ });
67264
+ var groupActiveCapability = {
67265
+ name: "group-active",
67266
+ scope: "device",
67267
+ deviceNative: true,
67268
+ mode: "singleton",
67269
+ deviceTypes: [
67270
+ DeviceType.Cover,
67271
+ DeviceType.Valve,
67272
+ DeviceType.Lock,
67273
+ DeviceType.MediaPlayer,
67274
+ DeviceType.Climate,
67275
+ DeviceType.Thermostat
67276
+ ],
67277
+ methods: {},
67278
+ status: {
67279
+ schema: GroupActiveSchema,
67280
+ kind: "push"
67281
+ },
67282
+ runtimeState: GroupActiveSchema,
67283
+ /**
67284
+ * Runtime-state durability: **session** — recomputed from the members on the
67285
+ * next source event; a restored value would outlive the members it named.
67286
+ *
67287
+ * See `RuntimeStateDurability`. Enforced by
67288
+ * `scripts/check-runtime-state-durability.ts`.
67289
+ */
67290
+ durability: "session",
67291
+ history: "none"
67292
+ };
67293
+ var GroupStatusSchema = external_exports.object({
67294
+ /** Members whose current value entered the aggregate. */
67295
+ included: external_exports.number().int().nonnegative().meta(readingMeta("count", {
67296
+ precision: 0,
67297
+ label: "Reporting"
67298
+ })),
67299
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
67300
+ excluded: external_exports.number().int().nonnegative().meta(readingMeta("count", {
67301
+ precision: 0,
67302
+ label: "Excluded"
67303
+ })),
67304
+ /** `included` + `excluded`. */
67305
+ total: external_exports.number().int().nonnegative().meta(readingMeta("count", {
67306
+ precision: 0,
67307
+ label: "Members"
67308
+ }))
67309
+ });
67310
+ var groupStatusCapability = {
67311
+ name: "group-status",
67312
+ scope: "device",
67313
+ deviceNative: true,
67314
+ mode: "singleton",
67315
+ deviceTypes: [
67316
+ DeviceType.Sensor,
67317
+ DeviceType.Switch,
67318
+ DeviceType.Light,
67319
+ DeviceType.Fan,
67320
+ DeviceType.Cover,
67321
+ DeviceType.Valve,
67322
+ DeviceType.Lock,
67323
+ DeviceType.MediaPlayer,
67324
+ DeviceType.Thermostat,
67325
+ DeviceType.Climate
67326
+ ],
67327
+ methods: {},
67328
+ status: {
67329
+ schema: GroupStatusSchema,
67330
+ kind: "push"
67331
+ },
67332
+ runtimeState: GroupStatusSchema,
67333
+ /**
67334
+ * Runtime-state durability: **session** — recomputed from members on the
67335
+ * next source event; a restored count would outlive the readings it named.
67336
+ *
67337
+ * See `RuntimeStateDurability`. Enforced by
67338
+ * `scripts/check-runtime-state-durability.ts`.
67339
+ */
67340
+ durability: "session",
67341
+ history: "none"
67342
+ };
66150
67343
  var HeatingValveStatusSchema = external_exports.object({
66151
67344
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
66152
- position: external_exports.number().min(0).max(100).nullable(),
67345
+ position: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
66153
67346
  /** Ms epoch when the slice was last updated (push or poll). */
66154
67347
  lastFetchedAt: external_exports.number()
66155
67348
  });
@@ -66177,9 +67370,9 @@ var HumidifierStatusSchema = external_exports.object({
66177
67370
  /** Whether the humidifier is currently on. */
66178
67371
  on: external_exports.boolean(),
66179
67372
  /** Current measured relative humidity (0..100). Null when not reported. */
66180
- currentHumidity: external_exports.number().min(0).max(100).nullable(),
67373
+ currentHumidity: external_exports.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
66181
67374
  /** Target relative humidity (0..100). Null when no setpoint surface. */
66182
- targetHumidity: external_exports.number().min(0).max(100).nullable(),
67375
+ targetHumidity: external_exports.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
66183
67376
  /** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
66184
67377
  * device has no mode surface. */
66185
67378
  mode: external_exports.string().nullable(),
@@ -66189,9 +67382,9 @@ var HumidifierStatusSchema = external_exports.object({
66189
67382
  * `idle` / `off`). Null when the device doesn't report it. */
66190
67383
  action: external_exports.string().nullable(),
66191
67384
  /** HA `min_humidity` attribute. Null → UI uses 0. */
66192
- minHumidity: external_exports.number().nullable(),
67385
+ minHumidity: external_exports.number().nullable().meta(readingMeta("humidity")),
66193
67386
  /** HA `max_humidity` attribute. Null → UI uses 100. */
66194
- maxHumidity: external_exports.number().nullable(),
67387
+ maxHumidity: external_exports.number().nullable().meta(readingMeta("humidity")),
66195
67388
  /** Ms epoch when the slice was last updated. */
66196
67389
  lastChangedAt: external_exports.number()
66197
67390
  });
@@ -66253,22 +67446,13 @@ var humidifierCapability = {
66253
67446
  } }
66254
67447
  };
66255
67448
  var HumiditySensorStatusSchema = external_exports.object({
66256
- /** Current relative humidity, 0..100. */
66257
- percent: external_exports.number().min(0).max(100).meta({
66258
- unit: "%",
67449
+ /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
67450
+ percent: external_exports.number().min(0).max(100).nullable().meta(readingMeta("humidity", {
67451
+ precision: 0,
66259
67452
  label: "Humidity"
66260
- }),
67453
+ })),
66261
67454
  /** Ms epoch when the slice was last updated. */
66262
- lastFetchedAt: external_exports.number(),
66263
- /** Live display unit from the upstream source (e.g. HA
66264
- * `attributes.unit_of_measurement`). The UI prefers this over the
66265
- * role's canonical unit. Absent → fall back to the canonical unit. */
66266
- unit: external_exports.string().optional(),
66267
- /** Suggested decimal places for numeric display.
66268
- * Populated live from the upstream source when provided (e.g. HA
66269
- * `attributes.suggested_display_precision`). Falls back to
66270
- * auto-formatting when absent. */
66271
- precision: external_exports.number().int().min(0).max(10).optional()
67455
+ lastFetchedAt: external_exports.number()
66272
67456
  });
66273
67457
  var humiditySensorCapability = {
66274
67458
  name: "humidity-sensor",
@@ -66299,19 +67483,14 @@ var humiditySensorCapability = {
66299
67483
  } } },
66300
67484
  /** Clock fields: written, but excluded from the compare that decides
66301
67485
  * whether persisting is worth a SQLite commit. */
66302
- volatileStateFields: ["lastFetchedAt"],
66303
- customize: {
66304
- version: 1,
66305
- advanced: "derive",
66306
- targets: []
66307
- }
67486
+ volatileStateFields: ["lastFetchedAt"]
66308
67487
  };
66309
67488
  var ImageStatusSchema = external_exports.object({
66310
67489
  /** Absolute signed URL the browser loads directly. Null when the
66311
67490
  * entity exposes no `entity_picture` (yet). */
66312
67491
  url: external_exports.string().nullable(),
66313
67492
  /** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
66314
- lastUpdated: external_exports.number().nullable()
67493
+ lastUpdated: external_exports.number().nullable().meta(readingMeta("none"))
66315
67494
  });
66316
67495
  var imageCapability = {
66317
67496
  name: "image",
@@ -66362,19 +67541,19 @@ var NormalizedRangeSchema = external_exports.object({
66362
67541
  });
66363
67542
  var ImageSettingsStatusSchema = external_exports.object({
66364
67543
  /** Normalized 0–100. */
66365
- brightness: external_exports.number().optional(),
67544
+ brightness: external_exports.number().optional().meta(readingMeta("none")),
66366
67545
  /** Normalized 0–100. */
66367
- contrast: external_exports.number().optional(),
67546
+ contrast: external_exports.number().optional().meta(readingMeta("none")),
66368
67547
  /** Normalized 0–100. */
66369
- saturation: external_exports.number().optional(),
67548
+ saturation: external_exports.number().optional().meta(readingMeta("none")),
66370
67549
  /** Normalized 0–100. */
66371
- sharpness: external_exports.number().optional(),
67550
+ sharpness: external_exports.number().optional().meta(readingMeta("none")),
66372
67551
  mirror: external_exports.boolean().optional(),
66373
67552
  flip: external_exports.boolean().optional(),
66374
67553
  rotate: ImageRotateSchema.optional(),
66375
67554
  whiteBalance: WhiteBalanceModeSchema.optional(),
66376
67555
  /** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
66377
- warmth: external_exports.number().optional(),
67556
+ warmth: external_exports.number().optional().meta(readingMeta("none")),
66378
67557
  exposureMode: ExposureModeSchema.optional(),
66379
67558
  backlightMode: BacklightModeSchema.optional(),
66380
67559
  lastFetchedAt: external_exports.number()
@@ -66612,10 +67791,10 @@ var IntercomAbilitySchema = external_exports.object({
66612
67791
  /** Codecs accepted by firmware, in preference order. Driver-authored strings. */
66613
67792
  codecs: external_exports.array(external_exports.string()),
66614
67793
  /** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
66615
- sampleRate: external_exports.number(),
67794
+ sampleRate: external_exports.number().meta(readingMeta("none")),
66616
67795
  duplex: external_exports.enum(["half", "full"]),
66617
67796
  /** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
66618
- maxBacklogMs: external_exports.number()
67797
+ maxBacklogMs: external_exports.number().meta(readingMeta("duration-ms"))
66619
67798
  });
66620
67799
  var IntercomStatusSchema = external_exports.object({
66621
67800
  /** True while a talk session is open. */
@@ -66812,13 +67991,13 @@ var LawnMowerControlStatusSchema = external_exports.object({
66812
67991
  activity: LawnMowerActivitySchema,
66813
67992
  /** 0..100 battery percentage. Null when the device has no battery
66814
67993
  * reading. */
66815
- batteryLevel: external_exports.number().min(0).max(100).nullable(),
67994
+ batteryLevel: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
66816
67995
  /** 0..100 mowing-completion percentage of the current task, or null when no
66817
67996
  * task is active / progress is unavailable. */
66818
- progressPercent: external_exports.number().min(0).max(100).nullable(),
67997
+ progressPercent: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
66819
67998
  /** Current device/event code (dynamic — mostly status, sometimes an error),
66820
67999
  * or null when unknown. */
66821
- currentCode: external_exports.number().nullable(),
68000
+ currentCode: external_exports.number().nullable().meta(readingMeta("none")),
66822
68001
  /** Human label for {@link currentCode}, or null when undecodable. */
66823
68002
  currentCodeLabel: external_exports.string().nullable(),
66824
68003
  /** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
@@ -67381,7 +68560,14 @@ var lockControlCapability = {
67381
68560
  }),
67382
68561
  unlock: method(external_exports.object({
67383
68562
  deviceId: external_exports.number().int().nonnegative(),
67384
- code: external_exports.string().min(1).optional()
68563
+ code: external_exports.string().min(1).optional(),
68564
+ /**
68565
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
68566
+ * with one call is refused unless the caller says it was confirmed. A
68567
+ * single lock ignores it. The refusal lives in the callee, so no
68568
+ * automation or API caller reaches the doors by skipping a dialog.
68569
+ */
68570
+ confirm: external_exports.boolean().optional()
67385
68571
  }), external_exports.void(), {
67386
68572
  kind: "mutation",
67387
68573
  auth: "protected"
@@ -67417,6 +68603,38 @@ var lockControlCapability = {
67417
68603
  * whether persisting is worth a SQLite commit. */
67418
68604
  volatileStateFields: ["lastChangedAt"]
67419
68605
  };
68606
+ var MeterStatusSchema = external_exports.object({
68607
+ value: external_exports.number().nullable().meta(readingMeta("device", { label: "Total" })),
68608
+ lastFetchedAt: external_exports.number()
68609
+ });
68610
+ var meterCapability = {
68611
+ name: "meter",
68612
+ scope: "device",
68613
+ deviceNative: true,
68614
+ mode: "singleton",
68615
+ deviceTypes: [DeviceType.Sensor],
68616
+ methods: {},
68617
+ status: {
68618
+ schema: MeterStatusSchema,
68619
+ kind: "push"
68620
+ },
68621
+ runtimeState: MeterStatusSchema,
68622
+ /**
68623
+ * Runtime-state durability: **restored** — the total is a cache of the
68624
+ * history integral. A restart shows it only until the history pass
68625
+ * recomputes the open period; it is not an in-memory buffer.
68626
+ *
68627
+ * See `RuntimeStateDurability`. Enforced by
68628
+ * `scripts/check-runtime-state-durability.ts`.
68629
+ */
68630
+ durability: "restored",
68631
+ history: { fields: { value: {
68632
+ kind: "counter",
68633
+ deadband: 1e-3,
68634
+ minIntervalMs: 6e4
68635
+ } } },
68636
+ volatileStateFields: ["lastFetchedAt"]
68637
+ };
67420
68638
  var MediaPlayerStateSchema = external_exports.enum([
67421
68639
  "off",
67422
68640
  "on",
@@ -67449,7 +68667,7 @@ var MediaPlayerStatusSchema = external_exports.object({
67449
68667
  state: MediaPlayerStateSchema,
67450
68668
  /** Volume as 0..100 inclusive. Null when the device has no volume
67451
68669
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
67452
- volumeLevel: external_exports.number().min(0).max(100).nullable(),
68670
+ volumeLevel: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
67453
68671
  /** Mute toggle distinct from volume=0. Null when no mute surface.
67454
68672
  * Pair with `DeviceFeature.MediaPlayerMute`. */
67455
68673
  isMuted: external_exports.boolean().nullable(),
@@ -67462,10 +68680,10 @@ var MediaPlayerStatusSchema = external_exports.object({
67462
68680
  currentMedia: MediaInfoSchema.nullable(),
67463
68681
  /** Current playback position in ms. Null when not seekable or
67464
68682
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
67465
- positionMs: external_exports.number().int().nonnegative().nullable(),
68683
+ positionMs: external_exports.number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
67466
68684
  /** Total duration of the current media in ms. Null when unknown
67467
68685
  * (live stream) or nothing is playing. */
67468
- durationMs: external_exports.number().int().nonnegative().nullable(),
68686
+ durationMs: external_exports.number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
67469
68687
  /** Shuffle toggle. Null when no shuffle surface.
67470
68688
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
67471
68689
  shuffle: external_exports.boolean().nullable(),
@@ -67810,7 +69028,7 @@ var motionCustomize = {
67810
69028
  eventName: "onMotionChanged"
67811
69029
  },
67812
69030
  deviceTypes: [DeviceType.Camera],
67813
- apply: "replace",
69031
+ apply: "add",
67814
69032
  applyAuthority: {
67815
69033
  kind: "camera-sensors",
67816
69034
  timeoutField: "motionCooldownMs"
@@ -67882,7 +69100,7 @@ var MotionStatusSchema = external_exports.object({
67882
69100
  * it, every provider seeded it at boot, and every session left it
67883
69101
  * `detected: true` after its detach.
67884
69102
  */
67885
- autoClearAfterMs: external_exports.number().nullable()
69103
+ autoClearAfterMs: external_exports.number().nullable().meta(readingMeta("duration-ms"))
67886
69104
  });
67887
69105
  var MotionOnMotionChangedDataSchema = external_exports.object({
67888
69106
  deviceId: external_exports.number(),
@@ -67913,13 +69131,19 @@ var motionCapability = {
67913
69131
  methods: {
67914
69132
  /**
67915
69133
  * Pull the current motion state synchronously. Convenience shortcut
67916
- * for consumers that don't need the full status object; equivalent
67917
- * to `getStatus()?.detected ?? false`. Will likely be folded into
67918
- * `getStatus` once the auto-injected status surface lands in every
67919
- * consumer.
69134
+ * for consumers that don't need the full status object. A composed
69135
+ * group answers from its slice (D944): unknown throws, it is not off.
67920
69136
  */
67921
69137
  isDetected: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.boolean())
67922
69138
  },
69139
+ /**
69140
+ * A composed motion group serves `isDetected` from `detected` (D944).
69141
+ * Without this the cap stays uncomposable (`has-commands`).
69142
+ */
69143
+ composedMethods: { isDetected: {
69144
+ kind: "slice",
69145
+ field: "detected"
69146
+ } },
67923
69147
  events: {
67924
69148
  /**
67925
69149
  * Fires every time the runner transitions a camera between
@@ -68023,7 +69247,7 @@ var MotionZoneRegionSchema = external_exports.object({
68023
69247
  });
68024
69248
  var MotionZoneStatusSchema = external_exports.object({
68025
69249
  enabled: external_exports.boolean(),
68026
- sensitivity: external_exports.number(),
69250
+ sensitivity: external_exports.number().meta(readingMeta("none")),
68027
69251
  /** Grid region(s). Today exactly one `grid` shape. */
68028
69252
  regions: external_exports.array(MotionZoneRegionSchema),
68029
69253
  lastFetchedAt: external_exports.number()
@@ -68247,7 +69471,7 @@ var NavigationStatusSchema = external_exports.object({
68247
69471
  following: external_exports.boolean(),
68248
69472
  flash: external_exports.boolean(),
68249
69473
  lightMode: NavigationLightModeSchema,
68250
- lightLevel: external_exports.number().min(40).max(100),
69474
+ lightLevel: external_exports.number().min(40).max(100).meta(readingMeta("none")),
68251
69475
  /** Ms epoch when the slice was last updated. */
68252
69476
  lastChangedAt: external_exports.number()
68253
69477
  });
@@ -68371,13 +69595,13 @@ var NetworkLinkStatusSchema = external_exports.object({
68371
69595
  * one whose reading has not landed must not be drawn at 0 %. Consumers
68372
69596
  * SKIP a null rather than coerce it.
68373
69597
  */
68374
- signalPercent: external_exports.number().min(0).max(100).nullable(),
69598
+ signalPercent: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
68375
69599
  /** Raw received signal strength in dBm, when the firmware reports one. */
68376
- rssiDbm: external_exports.number().optional(),
69600
+ rssiDbm: external_exports.number().optional().meta(readingMeta("signal-level")),
68377
69601
  /** Network name of a wireless link, when the firmware reports it. */
68378
69602
  ssid: external_exports.string().optional(),
68379
69603
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
68380
- lastUpdated: external_exports.number()
69604
+ lastUpdated: external_exports.number().meta(readingMeta("none"))
68381
69605
  });
68382
69606
  var NETWORK_LINK_UNKNOWN = {
68383
69607
  type: "unknown",
@@ -68745,7 +69969,7 @@ var NotifierStatusSchema = external_exports.object({
68745
69969
  lastError: external_exports.string().nullable(),
68746
69970
  /** Number of deliveries currently buffered server-side (rate-limited
68747
69971
  * notifiers may queue). 0 when the provider sends synchronously. */
68748
- queueDepth: external_exports.number().int().nonnegative(),
69972
+ queueDepth: external_exports.number().int().nonnegative().meta(readingMeta("count")),
68749
69973
  /** Per-feature capability matrix — authoritative source for the
68750
69974
  * compose-form field gating. */
68751
69975
  supports: NotifierSupportsSchema
@@ -68834,15 +70058,8 @@ var notifierCapability = {
68834
70058
  history: "none"
68835
70059
  };
68836
70060
  var NumericSensorStatusSchema = external_exports.object({
68837
- value: external_exports.number(),
68838
- /** Display unit-of-measurement (e.g. 'dBm', 's', 'rpm', 'steps').
68839
- * Populated live from the upstream source on each state push.
68840
- * Absent for unitless sensors. */
68841
- unit: external_exports.string().optional(),
68842
- /** Suggested decimal places for numeric display.
68843
- * Populated live from the upstream source when provided.
68844
- * Falls back to auto-formatting when absent. */
68845
- precision: external_exports.number().int().min(0).max(10).optional(),
70061
+ /** Reading in the device quantity's base unit. `null` when refused (D393). */
70062
+ value: external_exports.number().nullable().meta(readingMeta("device")),
68846
70063
  /** Ms epoch when the slice was last updated. */
68847
70064
  lastFetchedAt: external_exports.number()
68848
70065
  });
@@ -68866,11 +70083,11 @@ var numericSensorCapability = {
68866
70083
  */
68867
70084
  durability: "restored",
68868
70085
  /**
68869
- * History (D850): recorded series. The unit is per device, read from the sibling `unit` field.
70086
+ * History (D850): recorded series. The unit is the device quantity's base,
70087
+ * resolved when the series is read — the cap has no single unit.
68870
70088
  */
68871
70089
  history: { fields: { value: {
68872
70090
  kind: "gauge",
68873
- unitFrom: "unit",
68874
70091
  minIntervalMs: 3e4
68875
70092
  } } },
68876
70093
  /** Clock fields: written, but excluded from the compare that decides
@@ -69232,23 +70449,26 @@ var PetFeederStatusSchema = external_exports.object({
69232
70449
  /** Food currently in the bowl (grams). Null when the device has not
69233
70450
  * reported a reading yet. On dual-hopper models this is the combined
69234
70451
  * bowl reading; per-hopper levels live in `food1`/`food2`. */
69235
- foodLevel: external_exports.number().nullable(),
70452
+ foodLevel: external_exports.number().nullable().meta(readingMeta("none")),
69236
70453
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
69237
70454
  * single-hopper models. */
69238
- food1: external_exports.number().nullable(),
70455
+ food1: external_exports.number().nullable().meta(readingMeta("none")),
69239
70456
  /** Hopper-2 food level (grams) on dual-hopper feeders; null on
69240
70457
  * single-hopper models. */
69241
- food2: external_exports.number().nullable(),
70458
+ food2: external_exports.number().nullable().meta(readingMeta("none")),
69242
70459
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
69243
70460
  * (`device_class: problem`, on = low). True when the bowl is empty /
69244
70461
  * below the feeder's low threshold. */
69245
70462
  lowFood: external_exports.boolean(),
69246
70463
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
69247
70464
  * device has no battery reading. */
69248
- batteryPower: external_exports.number().min(0).max(100).nullable(),
69249
- /** Days of desiccant life remaining. Null when the model has no
69250
- * desiccant sensor. */
69251
- desiccantLeftDays: external_exports.number().nullable(),
70465
+ batteryPower: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
70466
+ /**
70467
+ * Desiccant life remaining, stored in seconds (duration base, D944).
70468
+ * Providers convert from the days the feeder reports. Null when the
70469
+ * model has no desiccant sensor.
70470
+ */
70471
+ desiccantLeftDays: external_exports.number().nullable().meta(readingMeta("duration")),
69252
70472
  /** True while a feed is in progress. */
69253
70473
  feeding: external_exports.boolean(),
69254
70474
  /** Decoded connectivity / power status (HA petkit device-status enum).
@@ -69259,7 +70479,7 @@ var PetFeederStatusSchema = external_exports.object({
69259
70479
  * with `errorCode` for consumers that want the raw integer. */
69260
70480
  error: external_exports.string().nullable(),
69261
70481
  /** Raw device error code (0 / null = no error). */
69262
- errorCode: external_exports.number().nullable(),
70482
+ errorCode: external_exports.number().nullable().meta(readingMeta("none")),
69263
70483
  /** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
69264
70484
  isDualHopper: external_exports.boolean(),
69265
70485
  /** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
@@ -69269,7 +70489,7 @@ var PetFeederStatusSchema = external_exports.object({
69269
70489
  /** Play a chime when dispensing. */
69270
70490
  feedSound: external_exports.boolean(),
69271
70491
  /** Speaker / prompt volume level (device-scaled integer). */
69272
- volume: external_exports.number(),
70492
+ volume: external_exports.number().meta(readingMeta("none")),
69273
70493
  /** Ms epoch when the slice was last refreshed from the cloud. */
69274
70494
  lastFetchedAt: external_exports.number()
69275
70495
  });
@@ -69388,7 +70608,7 @@ var petFeederCapability = {
69388
70608
  },
69389
70609
  desiccantLeftDays: {
69390
70610
  kind: "gauge",
69391
- unit: "days"
70611
+ unit: "s"
69392
70612
  }
69393
70613
  } }
69394
70614
  };
@@ -69824,113 +71044,79 @@ var platformProbeCapability = {
69824
71044
  };
69825
71045
  var PowerMeterStatusSchema = external_exports.object({
69826
71046
  /** Instantaneous power draw in watts. */
69827
- watts: external_exports.number().optional().meta({
69828
- unit: "W",
69829
- label: "Power"
69830
- }),
71047
+ watts: external_exports.number().optional().meta(readingMeta("power", { label: "Power" })),
69831
71048
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
69832
- kwhTotal: external_exports.number().optional().meta({
69833
- unit: "kWh",
69834
- label: "Energy"
69835
- }),
71049
+ kwhTotal: external_exports.number().optional().meta(readingMeta("energy", { label: "Energy" })),
69836
71050
  /** Voltage in volts. */
69837
- volts: external_exports.number().optional(),
71051
+ volts: external_exports.number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
69838
71052
  /** Current in amperes. */
69839
- amps: external_exports.number().optional(),
69840
- /** Apparent power in volt-amperes (W × power-factor reciprocal). */
69841
- va: external_exports.number().optional(),
71053
+ amps: external_exports.number().optional().meta(readingMeta("current", { label: "Current" })),
71054
+ /** Apparent power in volt-amperes. */
71055
+ va: external_exports.number().optional().meta(readingMeta("apparent-power")),
69842
71056
  /** Power factor (0..1) if reported. */
69843
- powerFactor: external_exports.number().min(0).max(1).optional(),
71057
+ powerFactor: external_exports.number().min(0).max(1).optional().meta(readingMeta("ratio")),
69844
71058
  /** Ms epoch when the slice was last updated. */
69845
- lastFetchedAt: external_exports.number(),
69846
- /** Live display unit of the single metric this slice carries (e.g. HA
69847
- * `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
69848
- * Each upstream `sensor.*` entity surfaces ONE device_class, so one
69849
- * unit per slice is unambiguous. The UI prefers this over the role's
69850
- * canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
69851
- unit: external_exports.string().optional(),
69852
- /** Suggested decimal places for numeric display.
69853
- * Populated live from the upstream source when provided (e.g. HA
69854
- * `attributes.suggested_display_precision`). Falls back to
69855
- * auto-formatting when absent. */
69856
- precision: external_exports.number().int().min(0).max(10).optional()
71059
+ lastFetchedAt: external_exports.number()
69857
71060
  });
69858
- var powerMeterCapability = {
69859
- name: "power-meter",
69860
- scope: "device",
69861
- deviceNative: true,
69862
- mode: "singleton",
69863
- deviceTypes: [DeviceType.Sensor],
69864
- methods: {},
69865
- status: {
69866
- schema: PowerMeterStatusSchema,
69867
- kind: "push"
69868
- },
69869
- runtimeState: PowerMeterStatusSchema,
69870
- /**
69871
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
69872
- *
69873
- * See `RuntimeStateDurability`. Enforced by
69874
- * `scripts/check-runtime-state-durability.ts`.
69875
- */
69876
- durability: "restored",
69877
- /**
69878
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
69879
- */
69880
- history: { fields: {
69881
- watts: {
69882
- kind: "gauge",
69883
- unit: "W",
69884
- deadband: 1,
69885
- minIntervalMs: 3e4
69886
- },
69887
- kwhTotal: {
69888
- kind: "counter",
69889
- unit: "kWh",
69890
- deadband: 0.01,
69891
- minIntervalMs: 6e4
69892
- },
69893
- volts: {
69894
- kind: "gauge",
69895
- unit: "V",
69896
- deadband: 1,
69897
- minIntervalMs: 3e4
69898
- },
69899
- amps: {
69900
- kind: "gauge",
69901
- unit: "A",
69902
- deadband: 0.05,
69903
- minIntervalMs: 3e4
69904
- },
69905
- va: {
69906
- kind: "gauge",
69907
- unit: "VA",
69908
- deadband: 1,
69909
- minIntervalMs: 3e4
71061
+ var POWER_METER_DEVICE_TYPES = [
71062
+ DeviceType.Sensor,
71063
+ DeviceType.Switch,
71064
+ DeviceType.Light,
71065
+ DeviceType.Fan,
71066
+ DeviceType.Climate,
71067
+ DeviceType.Thermostat,
71068
+ DeviceType.Humidifier,
71069
+ DeviceType.WaterHeater,
71070
+ DeviceType.MediaPlayer,
71071
+ DeviceType.Washer,
71072
+ DeviceType.Dryer,
71073
+ DeviceType.Dishwasher,
71074
+ DeviceType.Vacuum,
71075
+ DeviceType.LawnMower,
71076
+ DeviceType.PetFeeder
71077
+ ];
71078
+ var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
71079
+ function powerTarget(id, unit) {
71080
+ return {
71081
+ id,
71082
+ cardinality: "scalar",
71083
+ vocabulary: {
71084
+ cap: "power-meter",
71085
+ stateField: id
69910
71086
  },
69911
- powerFactor: {
69912
- kind: "gauge",
69913
- unit: "ratio",
69914
- deadband: 0.01,
69915
- minIntervalMs: 6e4
69916
- }
69917
- } },
69918
- /** Clock fields: written, but excluded from the compare that decides
69919
- * whether persisting is worth a SQLite commit. */
69920
- volatileStateFields: ["lastFetchedAt"],
69921
- customize: {
69922
- version: 1,
69923
- advanced: "derive",
69924
- targets: []
69925
- }
71087
+ deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
71088
+ apply: "add",
71089
+ path: id,
71090
+ sources: [{
71091
+ kind: "numeric",
71092
+ requiredUnit: unit,
71093
+ transforms: [{ kind: "identity" }]
71094
+ }],
71095
+ companions: [{
71096
+ kind: "clock",
71097
+ path: "lastFetchedAt",
71098
+ when: "always"
71099
+ }],
71100
+ sourceReport: { status: "assignment-status" },
71101
+ advancedExpression: true
71102
+ };
71103
+ }
71104
+ var powerMeterCustomize = {
71105
+ version: 1,
71106
+ targets: [
71107
+ powerTarget("watts", "W"),
71108
+ powerTarget("kwhTotal", "kWh"),
71109
+ powerTarget("volts", "V"),
71110
+ powerTarget("amps", "A")
71111
+ ]
69926
71112
  };
69927
71113
  var GpsLocationSchema = external_exports.object({
69928
71114
  /** Latitude in decimal degrees, -90..90. */
69929
- latitude: external_exports.number().min(-90).max(90),
71115
+ latitude: external_exports.number().min(-90).max(90).meta(readingMeta("angle")),
69930
71116
  /** Longitude in decimal degrees, -180..180. */
69931
- longitude: external_exports.number().min(-180).max(180),
71117
+ longitude: external_exports.number().min(-180).max(180).meta(readingMeta("angle")),
69932
71118
  /** Reported accuracy in meters (lower = better). */
69933
- accuracyMeters: external_exports.number().nonnegative()
71119
+ accuracyMeters: external_exports.number().nonnegative().meta(readingMeta("length"))
69934
71120
  });
69935
71121
  var PresenceStatusSchema = external_exports.object({
69936
71122
  /** `home` / `not_home` / any user-defined zone name. */
@@ -69942,7 +71128,7 @@ var PresenceStatusSchema = external_exports.object({
69942
71128
  gps: GpsLocationSchema.nullable(),
69943
71129
  /** Optional battery level of the tracking device (0..100). Null
69944
71130
  * when not reported. */
69945
- batteryPercent: external_exports.number().min(0).max(100).nullable(),
71131
+ batteryPercent: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
69946
71132
  /** Ms epoch when the slice was last updated. */
69947
71133
  lastChangedAt: external_exports.number()
69948
71134
  });
@@ -69984,19 +71170,10 @@ var presenceCapability = {
69984
71170
  volatileStateFields: ["lastChangedAt"]
69985
71171
  };
69986
71172
  var PressureSensorStatusSchema = external_exports.object({
69987
- /** Current pressure in hPa. */
69988
- hpa: external_exports.number(),
71173
+ /** Current pressure in hPa. `null` when the sample was refused (D393). */
71174
+ hpa: external_exports.number().nullable().meta(readingMeta("pressure", { precision: 0 })),
69989
71175
  /** Ms epoch when the slice was last updated. */
69990
- lastFetchedAt: external_exports.number(),
69991
- /** Live display unit from the upstream source (e.g. HA
69992
- * `attributes.unit_of_measurement`). The UI prefers this over the
69993
- * role's canonical unit. Absent → fall back to the canonical unit. */
69994
- unit: external_exports.string().optional(),
69995
- /** Suggested decimal places for numeric display.
69996
- * Populated live from the upstream source when provided (e.g. HA
69997
- * `attributes.suggested_display_precision`). Falls back to
69998
- * auto-formatting when absent. */
69999
- precision: external_exports.number().int().min(0).max(10).optional()
71176
+ lastFetchedAt: external_exports.number()
70000
71177
  });
70001
71178
  var pressureSensorCapability = {
70002
71179
  name: "pressure-sensor",
@@ -70377,8 +71554,8 @@ var ptzCapability = {
70377
71554
  var AutotrackTargetTypeSchema = external_exports.string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
70378
71555
  var PtzAutotrackSettingsSchema = external_exports.object({
70379
71556
  targetType: AutotrackTargetTypeSchema,
70380
- stopDelaySeconds: external_exports.number().int().min(0).max(300),
70381
- disappearDelaySeconds: external_exports.number().int().min(0).max(300)
71557
+ stopDelaySeconds: external_exports.number().int().min(0).max(300).meta(readingMeta("duration")),
71558
+ disappearDelaySeconds: external_exports.number().int().min(0).max(300).meta(readingMeta("duration"))
70382
71559
  });
70383
71560
  var PtzAutotrackTargetOptionSchema = external_exports.object({
70384
71561
  value: external_exports.string(),
@@ -70513,7 +71690,7 @@ var RunningStateStatusSchema = external_exports.object({
70513
71690
  /** null = unknown — never coerced to false (D393). */
70514
71691
  running: external_exports.boolean().nullable(),
70515
71692
  /** Epoch ms the current boolean began; null while `running` is null. */
70516
- since: external_exports.number().nullable(),
71693
+ since: external_exports.number().nullable().meta(readingMeta("none")),
70517
71694
  source: RunningStateSourceSchema.meta({ label: "Source" }),
70518
71695
  phase: external_exports.string().nullable(),
70519
71696
  /** null until a reading has been published (D393). */
@@ -70527,7 +71704,6 @@ var RunningFlipEventDataSchema = external_exports.object({
70527
71704
  var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
70528
71705
  var runningCustomize = {
70529
71706
  version: 1,
70530
- advanced: "derive",
70531
71707
  targets: [{
70532
71708
  id: "running",
70533
71709
  cardinality: "scalar",
@@ -70536,6 +71712,8 @@ var runningCustomize = {
70536
71712
  stateField: "running"
70537
71713
  },
70538
71714
  deviceTypes: [
71715
+ DeviceType.Washer,
71716
+ DeviceType.Dryer,
70539
71717
  DeviceType.Dishwasher,
70540
71718
  DeviceType.Vacuum,
70541
71719
  DeviceType.LawnMower,
@@ -70547,7 +71725,7 @@ var runningCustomize = {
70547
71725
  DeviceType.Thermostat,
70548
71726
  DeviceType.PetFeeder
70549
71727
  ],
70550
- apply: "add-or-replace",
71728
+ apply: "add",
70551
71729
  path: "running",
70552
71730
  sources: [
70553
71731
  {
@@ -70563,6 +71741,7 @@ var runningCustomize = {
70563
71741
  requiredUnit: "W",
70564
71742
  transforms: [{
70565
71743
  kind: "threshold",
71744
+ comparisons: ["gte", "lte"],
70566
71745
  comparison: "gte",
70567
71746
  defaultThreshold: 5,
70568
71747
  defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
@@ -71762,9 +72941,9 @@ var RecordTriggerSchema = external_exports.enum([
71762
72941
  ]);
71763
72942
  var RecordWindowSchema = external_exports.object({
71764
72943
  trigger: RecordTriggerSchema,
71765
- day: external_exports.number().int().min(0).max(6),
71766
- startMinute: external_exports.number().int().min(0).max(1439),
71767
- endMinute: external_exports.number().int().min(1).max(1440)
72944
+ day: external_exports.number().int().min(0).max(6).meta(readingMeta("none")),
72945
+ startMinute: external_exports.number().int().min(0).max(1439).meta(readingMeta("none")),
72946
+ endMinute: external_exports.number().int().min(1).max(1440).meta(readingMeta("none"))
71768
72947
  });
71769
72948
  var OnboardStorageVolumeSchema = external_exports.object({
71770
72949
  /** The camera's own id for the volume (`hdd/id`, Reolink `HddInfo/number`). */
@@ -71834,10 +73013,10 @@ var RecordingOnboardStatusSchema = external_exports.object({
71834
73013
  /** Master "record to the card at all" switch. */
71835
73014
  enabled: external_exports.boolean().nullable(),
71836
73015
  overwriteWhenFull: external_exports.boolean().nullable(),
71837
- preRecordSec: external_exports.number().nullable(),
71838
- postRecordSec: external_exports.number().nullable(),
73016
+ preRecordSec: external_exports.number().nullable().meta(readingMeta("duration")),
73017
+ postRecordSec: external_exports.number().nullable().meta(readingMeta("duration")),
71839
73018
  /** Length of one recorded file, in minutes. */
71840
- segmentMinutes: external_exports.number().nullable(),
73019
+ segmentMinutes: external_exports.number().nullable().meta(readingMeta("none")),
71841
73020
  /** The primary track's weekly windows, flattened. */
71842
73021
  windows: external_exports.array(RecordWindowSchema),
71843
73022
  /**
@@ -71853,7 +73032,7 @@ var RecordingOnboardStatusSchema = external_exports.object({
71853
73032
  * provider reporting a non-zero count also reports the schedule as not
71854
73033
  * writable.
71855
73034
  */
71856
- unreadableWindows: external_exports.number(),
73035
+ unreadableWindows: external_exports.number().meta(readingMeta("count")),
71857
73036
  /**
71858
73037
  * The camera is scheduled to record and has NO usable storage.
71859
73038
  *
@@ -72469,7 +73648,7 @@ var CamStreamDescriptorSchema = external_exports.object({
72469
73648
  url: external_exports.string().optional(),
72470
73649
  codec: external_exports.string().optional(),
72471
73650
  resolution: CamStreamResolutionSchema.optional(),
72472
- fps: external_exports.number().positive().optional(),
73651
+ fps: external_exports.number().positive().optional().meta(readingMeta("rate")),
72473
73652
  label: external_exports.string().optional(),
72474
73653
  /** Device-level features (e.g. `battery-operated`) — drives broker policy. */
72475
73654
  deviceFeatures: external_exports.array(external_exports.string()).optional(),
@@ -72525,18 +73704,18 @@ var StreamProfileSchema = external_exports.enum([
72525
73704
  "ext"
72526
73705
  ]);
72527
73706
  var StreamProfileConfigSchema = external_exports.object({
72528
- width: external_exports.number(),
72529
- height: external_exports.number(),
73707
+ width: external_exports.number().meta(readingMeta("none")),
73708
+ height: external_exports.number().meta(readingMeta("none")),
72530
73709
  codec: external_exports.enum(["h264", "h265"]),
72531
- framerate: external_exports.number(),
72532
- bitrate: external_exports.number(),
73710
+ framerate: external_exports.number().meta(readingMeta("rate")),
73711
+ bitrate: external_exports.number().meta(readingMeta("bitrate")),
72533
73712
  bitrateMode: external_exports.enum(["vbr", "cbr"]).optional(),
72534
73713
  encoderProfile: external_exports.enum([
72535
73714
  "high",
72536
73715
  "main",
72537
73716
  "baseline"
72538
73717
  ]).optional(),
72539
- gop: external_exports.number().optional(),
73718
+ gop: external_exports.number().optional().meta(readingMeta("none")),
72540
73719
  /**
72541
73720
  * Whether THIS profile currently carries an audio track. READ-ONLY here.
72542
73721
  *
@@ -72694,7 +73873,8 @@ var switchCapability = {
72694
73873
  deviceTypes: [
72695
73874
  DeviceType.Switch,
72696
73875
  DeviceType.Siren,
72697
- DeviceType.Light
73876
+ DeviceType.Light,
73877
+ DeviceType.Fan
72698
73878
  ],
72699
73879
  methods: { setState: method(external_exports.object({
72700
73880
  deviceId: external_exports.number(),
@@ -72741,12 +73921,7 @@ var switchCapability = {
72741
73921
  label: "On",
72742
73922
  kind: "boolean"
72743
73923
  }
72744
- }] },
72745
- customize: {
72746
- version: 1,
72747
- advanced: "derive",
72748
- targets: []
72749
- }
73924
+ }] }
72750
73925
  };
72751
73926
  function hasControlCharacter(value) {
72752
73927
  for (const char of value) {
@@ -73231,23 +74406,13 @@ var tamperCapability = {
73231
74406
  volatileStateFields: ["lastChangedAt"]
73232
74407
  };
73233
74408
  var TemperatureSensorStatusSchema = external_exports.object({
73234
- /** Current temperature in Celsius. */
73235
- celsius: external_exports.number().meta({
73236
- unit: "\xB0C",
74409
+ /** Current temperature in Celsius. `null` when the sample was refused (D393). */
74410
+ celsius: external_exports.number().nullable().meta(readingMeta("temperature", {
74411
+ precision: 1,
73237
74412
  label: "Temperature"
73238
- }),
74413
+ })),
73239
74414
  /** Ms epoch when the slice was last updated (push or poll). */
73240
- lastFetchedAt: external_exports.number(),
73241
- /** Live display unit from the upstream source (e.g. HA
73242
- * `attributes.unit_of_measurement`). The UI prefers this over the
73243
- * role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
73244
- * Absent → the UI falls back to the role's canonical unit. */
73245
- unit: external_exports.string().optional(),
73246
- /** Suggested decimal places for numeric display.
73247
- * Populated live from the upstream source when provided (e.g. HA
73248
- * `attributes.suggested_display_precision`). Falls back to
73249
- * auto-formatting when absent. */
73250
- precision: external_exports.number().int().min(0).max(10).optional()
74415
+ lastFetchedAt: external_exports.number()
73251
74416
  });
73252
74417
  var temperatureSensorCapability = {
73253
74418
  name: "temperature-sensor",
@@ -73278,12 +74443,7 @@ var temperatureSensorCapability = {
73278
74443
  } } },
73279
74444
  /** Clock fields: written, but excluded from the compare that decides
73280
74445
  * whether persisting is worth a SQLite commit. */
73281
- volatileStateFields: ["lastFetchedAt"],
73282
- customize: {
73283
- version: 1,
73284
- advanced: "derive",
73285
- targets: []
73286
- }
74446
+ volatileStateFields: ["lastFetchedAt"]
73287
74447
  };
73288
74448
  var ToastSchema = external_exports.object({
73289
74449
  title: external_exports.string(),
@@ -73575,16 +74735,16 @@ var VacuumControlStatusSchema = external_exports.object({
73575
74735
  state: VacuumStateSchema,
73576
74736
  /** 0..100 battery percentage. Null when the device has no battery
73577
74737
  * reading. */
73578
- batteryLevel: external_exports.number().min(0).max(100).nullable(),
74738
+ batteryLevel: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
73579
74739
  /** Current fan-speed token (provider-verbatim). Null when unknown or
73580
74740
  * the vacuum has no speed control. */
73581
74741
  fanSpeed: external_exports.string().nullable(),
73582
74742
  /** Speed tokens the hardware accepts — drives the UI selector. */
73583
74743
  availableFanSpeeds: external_exports.array(external_exports.string()),
73584
74744
  /** 0..100 cleaning-completion percentage of the current task, or null. */
73585
- progressPercent: external_exports.number().min(0).max(100).nullable(),
74745
+ progressPercent: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
73586
74746
  /** Current error code (0 / null = no error). */
73587
- errorCode: external_exports.number().nullable(),
74747
+ errorCode: external_exports.number().nullable().meta(readingMeta("none")),
73588
74748
  /** Human label for {@link errorCode}, or null when none / undecodable. */
73589
74749
  errorLabel: external_exports.string().nullable(),
73590
74750
  /** Ms epoch when the slice was last updated. */
@@ -73663,7 +74823,7 @@ var ValveStatusSchema = external_exports.object({
73663
74823
  state: ValveStateSchema,
73664
74824
  /** 0 = fully closed, 100 = fully open. Null when the device has no
73665
74825
  * intermediate position surface. */
73666
- position: external_exports.number().min(0).max(100).nullable(),
74826
+ position: external_exports.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
73667
74827
  /** Ms epoch when the slice was last updated. */
73668
74828
  lastChangedAt: external_exports.number()
73669
74829
  });
@@ -73753,9 +74913,9 @@ var vibrationCapability = {
73753
74913
  };
73754
74914
  var WaterHeaterStatusSchema = external_exports.object({
73755
74915
  /** Current measured temperature. Null when not reported. */
73756
- currentTemp: external_exports.number().nullable(),
74916
+ currentTemp: external_exports.number().nullable().meta(readingMeta("temperature")),
73757
74917
  /** Target temperature setpoint. Null when no setpoint surface. */
73758
- targetTemp: external_exports.number().nullable(),
74918
+ targetTemp: external_exports.number().nullable().meta(readingMeta("temperature")),
73759
74919
  /** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
73760
74920
  * `heat_pump` / `high_demand` / `performance` / `off`). Null when the
73761
74921
  * device reports an unknown state. */
@@ -73766,9 +74926,9 @@ var WaterHeaterStatusSchema = external_exports.object({
73766
74926
  * has no away surface. */
73767
74927
  away: external_exports.boolean().nullable(),
73768
74928
  /** HA `min_temp` attribute. Null when not reported. */
73769
- minTemp: external_exports.number().nullable(),
74929
+ minTemp: external_exports.number().nullable().meta(readingMeta("temperature")),
73770
74930
  /** HA `max_temp` attribute. Null when not reported. */
73771
- maxTemp: external_exports.number().nullable(),
74931
+ maxTemp: external_exports.number().nullable().meta(readingMeta("temperature")),
73772
74932
  /** Ms epoch when the slice was last updated. */
73773
74933
  lastChangedAt: external_exports.number()
73774
74934
  });
@@ -73834,25 +74994,18 @@ var waterHeaterCapability = {
73834
74994
  } }
73835
74995
  };
73836
74996
  var WeatherStatusSchema = external_exports.object({
73837
- /** Verbatim HA condition state (`sunny`, `cloudy`, `rainy`, …). Null
73838
- * when no condition has been reported yet. */
74997
+ /** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
73839
74998
  condition: external_exports.string().nullable(),
73840
- /** Current temperature in the reported unit. Null when not provided. */
73841
- temperature: external_exports.number().nullable(),
73842
- /** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
73843
- temperatureUnit: external_exports.string().nullable(),
74999
+ /** Current temperature in Celsius. Null when not provided or refused. */
75000
+ temperature: external_exports.number().nullable().meta(readingMeta("temperature", { precision: 1 })),
73844
75001
  /** Relative humidity (0..100). Null when not provided. */
73845
- humidity: external_exports.number().min(0).max(100).nullable(),
73846
- /** Barometric pressure in the reported unit. Null when not provided. */
73847
- pressure: external_exports.number().nullable(),
73848
- /** Pressure unit string (e.g. `hPa` / `inHg`). Null when not provided. */
73849
- pressureUnit: external_exports.string().nullable(),
73850
- /** Wind speed in the reported unit. Null when not provided. */
73851
- windSpeed: external_exports.number().nullable(),
73852
- /** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
73853
- windSpeedUnit: external_exports.string().nullable(),
75002
+ humidity: external_exports.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
75003
+ /** Barometric pressure in hPa. Null when not provided or refused. */
75004
+ pressure: external_exports.number().nullable().meta(readingMeta("pressure")),
75005
+ /** Wind speed in metres per second. Null when not provided or refused. */
75006
+ windSpeed: external_exports.number().nullable().meta(readingMeta("speed")),
73854
75007
  /** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
73855
- windBearing: external_exports.number().nullable(),
75008
+ windBearing: external_exports.number().nullable().meta(readingMeta("angle")),
73856
75009
  /** Ms epoch when the slice was last updated. */
73857
75010
  lastFetchedAt: external_exports.number()
73858
75011
  });
@@ -73880,12 +75033,12 @@ var weatherCapability = {
73880
75033
  */
73881
75034
  durability: "session",
73882
75035
  /**
73883
- * History (D850): recorded series. Units follow the sibling `*Unit` fields.
75036
+ * History (D850): recorded series. Numbers are the quantity base (D944).
73884
75037
  */
73885
75038
  history: { fields: {
73886
75039
  temperature: {
73887
75040
  kind: "gauge",
73888
- unitFrom: "temperatureUnit",
75041
+ unit: "\xB0C",
73889
75042
  deadband: 0.2
73890
75043
  },
73891
75044
  humidity: {
@@ -73895,12 +75048,12 @@ var weatherCapability = {
73895
75048
  },
73896
75049
  pressure: {
73897
75050
  kind: "gauge",
73898
- unitFrom: "pressureUnit",
75051
+ unit: "hPa",
73899
75052
  deadband: 0.5
73900
75053
  },
73901
75054
  windSpeed: {
73902
75055
  kind: "gauge",
73903
- unitFrom: "windSpeedUnit",
75056
+ unit: "m/s",
73904
75057
  deadband: 0.5
73905
75058
  }
73906
75059
  } }
@@ -74719,6 +75872,52 @@ var PIPELINE_OWNER_CAPABILITY_NAMES = [
74719
75872
  "pipeline-orchestrator",
74720
75873
  "pipeline-runner"
74721
75874
  ];
75875
+ function row$1(cap, method2, requires = null, confirm2 = false) {
75876
+ return {
75877
+ cap,
75878
+ method: method2,
75879
+ requires,
75880
+ confirm: confirm2
75881
+ };
75882
+ }
75883
+ var ACTUATOR_METHODS = {
75884
+ switch: [row$1("switch", "setState")],
75885
+ light: [
75886
+ row$1("switch", "setState"),
75887
+ row$1("brightness", "setBrightness"),
75888
+ row$1("color", "setColor")
75889
+ ],
75890
+ fan: [
75891
+ row$1("switch", "setState"),
75892
+ row$1("fan-control", "setPercentage", DeviceFeature.FanSpeed),
75893
+ row$1("fan-control", "setPreset", DeviceFeature.FanPreset),
75894
+ row$1("fan-control", "setDirection", DeviceFeature.FanDirection),
75895
+ row$1("fan-control", "setOscillating", DeviceFeature.FanOscillating)
75896
+ ],
75897
+ cover: [
75898
+ row$1("cover", "open"),
75899
+ row$1("cover", "close"),
75900
+ row$1("cover", "stop"),
75901
+ row$1("cover", "setPosition", DeviceFeature.CoverPositionable),
75902
+ row$1("cover", "setTiltPosition", DeviceFeature.CoverTilt)
75903
+ ],
75904
+ valve: [
75905
+ row$1("valve", "open"),
75906
+ row$1("valve", "close"),
75907
+ row$1("valve", "setPosition", DeviceFeature.ValvePositionable)
75908
+ ],
75909
+ lock: [row$1("lock-control", "lock"), row$1("lock-control", "unlock", null, true)],
75910
+ "media-player": [
75911
+ row$1("media-player", "play"),
75912
+ row$1("media-player", "pause"),
75913
+ row$1("media-player", "setVolume", DeviceFeature.MediaPlayerVolume)
75914
+ ],
75915
+ climate: [
75916
+ row$1("climate-control", "setMode"),
75917
+ row$1("climate-control", "setTarget"),
75918
+ row$1("climate-control", "setFanMode", DeviceFeature.ClimateFanMode)
75919
+ ]
75920
+ };
74722
75921
  var UNIT_TABLE = {
74723
75922
  "\xB0C": {
74724
75923
  dimension: "temperature",
@@ -74840,6 +76039,11 @@ var UNIT_TABLE = {
74840
76039
  factor: 1609.344,
74841
76040
  offset: 0
74842
76041
  },
76042
+ "m\xB2": {
76043
+ dimension: "area",
76044
+ factor: 1,
76045
+ offset: 0
76046
+ },
74843
76047
  lx: {
74844
76048
  dimension: "illuminance",
74845
76049
  factor: 1,
@@ -74944,20 +76148,125 @@ var UNIT_TABLE = {
74944
76148
  dimension: "percentage",
74945
76149
  factor: 1,
74946
76150
  offset: 0
76151
+ },
76152
+ L: {
76153
+ dimension: "volume",
76154
+ factor: 1,
76155
+ offset: 0
76156
+ },
76157
+ mL: {
76158
+ dimension: "volume",
76159
+ factor: 1e-3,
76160
+ offset: 0
76161
+ },
76162
+ gal: {
76163
+ dimension: "volume",
76164
+ factor: 3.785411784,
76165
+ offset: 0
76166
+ },
76167
+ s: {
76168
+ dimension: "duration",
76169
+ factor: 1,
76170
+ offset: 0
76171
+ },
76172
+ ms: {
76173
+ dimension: "duration",
76174
+ factor: 1e-3,
76175
+ offset: 0
76176
+ },
76177
+ min: {
76178
+ dimension: "duration",
76179
+ factor: 60,
76180
+ offset: 0
76181
+ },
76182
+ h: {
76183
+ dimension: "duration",
76184
+ factor: 3600,
76185
+ offset: 0
76186
+ },
76187
+ d: {
76188
+ dimension: "duration",
76189
+ factor: 86400,
76190
+ offset: 0
76191
+ },
76192
+ B: {
76193
+ dimension: "information",
76194
+ factor: 1,
76195
+ offset: 0
76196
+ },
76197
+ KiB: {
76198
+ dimension: "information",
76199
+ factor: 1024,
76200
+ offset: 0
76201
+ },
76202
+ MiB: {
76203
+ dimension: "information",
76204
+ factor: 1024 ** 2,
76205
+ offset: 0
76206
+ },
76207
+ GiB: {
76208
+ dimension: "information",
76209
+ factor: 1024 ** 3,
76210
+ offset: 0
76211
+ },
76212
+ TiB: {
76213
+ dimension: "information",
76214
+ factor: 1024 ** 4,
76215
+ offset: 0
76216
+ },
76217
+ kB: {
76218
+ dimension: "information",
76219
+ factor: 1e3,
76220
+ offset: 0
76221
+ },
76222
+ MB: {
76223
+ dimension: "information",
76224
+ factor: 1e6,
76225
+ offset: 0
76226
+ },
76227
+ GB: {
76228
+ dimension: "information",
76229
+ factor: 1e9,
76230
+ offset: 0
76231
+ },
76232
+ "\xB0": {
76233
+ dimension: "angle",
76234
+ factor: 1,
76235
+ offset: 0
76236
+ },
76237
+ dBFS: {
76238
+ dimension: "sound-level",
76239
+ factor: 1,
76240
+ offset: 0
76241
+ },
76242
+ dBm: {
76243
+ dimension: "signal-level",
76244
+ factor: 1,
76245
+ offset: 0
76246
+ },
76247
+ mired: {
76248
+ dimension: "colour-temperature",
76249
+ factor: 1,
76250
+ offset: 0
76251
+ },
76252
+ kbps: {
76253
+ dimension: "bitrate",
76254
+ factor: 1,
76255
+ offset: 0
76256
+ },
76257
+ Mbps: {
76258
+ dimension: "bitrate",
76259
+ factor: 1e3,
76260
+ offset: 0
76261
+ },
76262
+ fps: {
76263
+ dimension: "rate",
76264
+ factor: 1,
76265
+ offset: 0
74947
76266
  }
74948
76267
  };
74949
76268
  var INVERTIBLE_CAPS = SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
74950
76269
  var CAP_CUSTOMIZE_CATALOG = {
74951
- "ambient-light-sensor": {
74952
- version: 1,
74953
- targets: [],
74954
- advancedParameters: [{
74955
- path: "lux",
74956
- kind: "number",
74957
- label: "Illuminance",
74958
- unit: "lx"
74959
- }]
74960
- },
74961
76270
  "battery": {
74962
76271
  version: 1,
74963
76272
  targets: [{
@@ -74970,15 +76279,23 @@ var CAP_CUSTOMIZE_CATALOG = {
74970
76279
  DeviceType.Switch,
74971
76280
  DeviceType.PetFeeder,
74972
76281
  DeviceType.Container,
74973
- DeviceType.Thermostat
76282
+ DeviceType.Thermostat,
76283
+ DeviceType.EventEmitter
74974
76284
  ],
74975
- apply: "add-or-replace",
76285
+ apply: "add",
74976
76286
  vocabularyCap: "battery",
74977
76287
  vocabularyStateField: "percentage",
74978
76288
  sources: [{
74979
76289
  kind: "field",
74980
76290
  valueKinds: ["number", "string"],
74981
- transformKinds: ["identity", "linear"]
76291
+ transformKinds: ["identity", "linear"],
76292
+ transforms: [{ kind: "identity" }, {
76293
+ kind: "linear",
76294
+ defaultScale: 1,
76295
+ defaultOffset: 0,
76296
+ clampMin: 0,
76297
+ clampMax: 100
76298
+ }]
74982
76299
  }],
74983
76300
  sourceReport: { status: "assignment-status" },
74984
76301
  advancedExpression: true,
@@ -75004,38 +76321,6 @@ var CAP_CUSTOMIZE_CATALOG = {
75004
76321
  when: "add"
75005
76322
  }
75006
76323
  ]
75007
- }],
75008
- advancedParameters: [
75009
- {
75010
- path: "binary",
75011
- kind: "boolean",
75012
- label: "Binary indicator"
75013
- },
75014
- {
75015
- path: "charging",
75016
- kind: "enum",
75017
- label: "Charging source",
75018
- enumValues: [
75019
- "dc",
75020
- "solar",
75021
- "none",
75022
- "unknown"
75023
- ]
75024
- },
75025
- {
75026
- path: "sleeping",
75027
- kind: "boolean",
75028
- label: "Sleeping"
75029
- }
75030
- ]
75031
- },
75032
- "binary": {
75033
- version: 1,
75034
- targets: [],
75035
- advancedParameters: [{
75036
- path: "on",
75037
- kind: "boolean",
75038
- label: "On"
75039
76324
  }]
75040
76325
  },
75041
76326
  "consumables": {
@@ -75075,7 +76360,9 @@ var CAP_CUSTOMIZE_CATALOG = {
75075
76360
  DeviceType.Container,
75076
76361
  DeviceType.Image,
75077
76362
  DeviceType.PetFeeder,
75078
- DeviceType.Dishwasher
76363
+ DeviceType.Dishwasher,
76364
+ DeviceType.Washer,
76365
+ DeviceType.Dryer
75079
76366
  ],
75080
76367
  apply: "add",
75081
76368
  vocabularyCap: "consumables",
@@ -75093,7 +76380,14 @@ var CAP_CUSTOMIZE_CATALOG = {
75093
76380
  nullable: true,
75094
76381
  sources: [{
75095
76382
  kind: "numeric",
75096
- transformKinds: ["identity", "linear"]
76383
+ transformKinds: ["identity", "linear"],
76384
+ transforms: [{ kind: "identity" }, {
76385
+ kind: "linear",
76386
+ defaultScale: 1,
76387
+ defaultOffset: 0,
76388
+ clampMin: 0,
76389
+ clampMax: 100
76390
+ }]
75097
76391
  }]
75098
76392
  },
75099
76393
  {
@@ -75102,15 +76396,12 @@ var CAP_CUSTOMIZE_CATALOG = {
75102
76396
  nullable: true,
75103
76397
  sources: [{
75104
76398
  kind: "numeric",
75105
- transformKinds: ["identity"]
76399
+ transformKinds: ["identity"],
76400
+ transforms: [{ kind: "identity" }]
75106
76401
  }],
75107
76402
  literals: [{
75108
- path: "remaining.unit",
75109
- values: [
75110
- "days",
75111
- "hours",
75112
- "cycles"
75113
- ]
76403
+ path: "remaining.kind",
76404
+ values: ["duration", "count"]
75114
76405
  }]
75115
76406
  },
75116
76407
  {
@@ -75126,7 +76417,18 @@ var CAP_CUSTOMIZE_CATALOG = {
75126
76417
  ],
75127
76418
  sources: [{
75128
76419
  kind: "enum",
75129
- transformKinds: ["enum-map"]
76420
+ transformKinds: ["enum-map"],
76421
+ transforms: [{
76422
+ kind: "enum-map",
76423
+ outputValues: [
76424
+ "ok",
76425
+ "low",
76426
+ "empty",
76427
+ "full",
76428
+ "replace"
76429
+ ],
76430
+ unmapped: null
76431
+ }]
75130
76432
  }]
75131
76433
  }
75132
76434
  ],
@@ -75157,8 +76459,7 @@ var CAP_CUSTOMIZE_CATALOG = {
75157
76459
  path: "lastFetchedAt",
75158
76460
  when: "add"
75159
76461
  }]
75160
- }],
75161
- advancedParameters: []
76462
+ }]
75162
76463
  },
75163
76464
  "doorbell": {
75164
76465
  version: 1,
@@ -75171,10 +76472,12 @@ var CAP_CUSTOMIZE_CATALOG = {
75171
76472
  vocabularyEvent: "onPressed",
75172
76473
  sources: [{
75173
76474
  kind: "binary",
75174
- transformKinds: []
76475
+ transformKinds: [],
76476
+ transforms: []
75175
76477
  }, {
75176
76478
  kind: "switch",
75177
- transformKinds: []
76479
+ transformKinds: [],
76480
+ transforms: []
75178
76481
  }],
75179
76482
  sourceReport: { status: "assignment-status" },
75180
76483
  advancedExpression: true,
@@ -75183,21 +76486,11 @@ var CAP_CUSTOMIZE_CATALOG = {
75183
76486
  eventName: "onPressed",
75184
76487
  combine: "any",
75185
76488
  edges: ["rising"],
76489
+ defaultEdge: "rising",
75186
76490
  timestampPath: "lastPressedAt",
75187
76491
  counterPath: "pressCountSinceStart",
75188
76492
  highWater: "composer-advance",
75189
76493
  debounceMs: 2e3
75190
- }],
75191
- advancedParameters: []
75192
- },
75193
- "humidity-sensor": {
75194
- version: 1,
75195
- targets: [],
75196
- advancedParameters: [{
75197
- path: "percent",
75198
- kind: "number",
75199
- label: "Humidity",
75200
- unit: "%"
75201
76494
  }]
75202
76495
  },
75203
76496
  "motion": {
@@ -75206,15 +76499,17 @@ var CAP_CUSTOMIZE_CATALOG = {
75206
76499
  id: "detected",
75207
76500
  cardinality: "event",
75208
76501
  deviceTypes: [DeviceType.Camera],
75209
- apply: "replace",
76502
+ apply: "add",
75210
76503
  vocabularyCap: "motion",
75211
76504
  vocabularyEvent: "onMotionChanged",
75212
76505
  sources: [{
75213
76506
  kind: "binary",
75214
- transformKinds: []
76507
+ transformKinds: [],
76508
+ transforms: []
75215
76509
  }, {
75216
76510
  kind: "switch",
75217
- transformKinds: []
76511
+ transformKinds: [],
76512
+ transforms: []
75218
76513
  }],
75219
76514
  sourceReport: { status: "assignment-status" },
75220
76515
  advancedExpression: false,
@@ -75233,23 +76528,168 @@ var CAP_CUSTOMIZE_CATALOG = {
75233
76528
  "confirm",
75234
76529
  "replace"
75235
76530
  ]
75236
- }],
75237
- advancedParameters: []
76531
+ }]
75238
76532
  },
75239
76533
  "power-meter": {
75240
76534
  version: 1,
75241
- targets: [],
75242
- advancedParameters: [{
75243
- path: "kwhTotal",
75244
- kind: "number",
75245
- label: "Energy",
75246
- unit: "kWh"
75247
- }, {
75248
- path: "watts",
75249
- kind: "number",
75250
- label: "Power",
75251
- unit: "W"
75252
- }]
76535
+ targets: [
76536
+ {
76537
+ id: "watts",
76538
+ cardinality: "scalar",
76539
+ deviceTypes: [
76540
+ DeviceType.Switch,
76541
+ DeviceType.Light,
76542
+ DeviceType.Fan,
76543
+ DeviceType.Climate,
76544
+ DeviceType.Thermostat,
76545
+ DeviceType.Humidifier,
76546
+ DeviceType.WaterHeater,
76547
+ DeviceType.MediaPlayer,
76548
+ DeviceType.Washer,
76549
+ DeviceType.Dryer,
76550
+ DeviceType.Dishwasher,
76551
+ DeviceType.Vacuum,
76552
+ DeviceType.LawnMower,
76553
+ DeviceType.PetFeeder
76554
+ ],
76555
+ apply: "add",
76556
+ vocabularyCap: "power-meter",
76557
+ vocabularyStateField: "watts",
76558
+ sources: [{
76559
+ kind: "numeric",
76560
+ requiredUnit: "W",
76561
+ transformKinds: ["identity"],
76562
+ transforms: [{ kind: "identity" }]
76563
+ }],
76564
+ sourceReport: { status: "assignment-status" },
76565
+ advancedExpression: true,
76566
+ path: "watts",
76567
+ valueKind: "number",
76568
+ nullable: false,
76569
+ companions: [{
76570
+ kind: "clock",
76571
+ path: "lastFetchedAt",
76572
+ when: "always"
76573
+ }]
76574
+ },
76575
+ {
76576
+ id: "kwhTotal",
76577
+ cardinality: "scalar",
76578
+ deviceTypes: [
76579
+ DeviceType.Switch,
76580
+ DeviceType.Light,
76581
+ DeviceType.Fan,
76582
+ DeviceType.Climate,
76583
+ DeviceType.Thermostat,
76584
+ DeviceType.Humidifier,
76585
+ DeviceType.WaterHeater,
76586
+ DeviceType.MediaPlayer,
76587
+ DeviceType.Washer,
76588
+ DeviceType.Dryer,
76589
+ DeviceType.Dishwasher,
76590
+ DeviceType.Vacuum,
76591
+ DeviceType.LawnMower,
76592
+ DeviceType.PetFeeder
76593
+ ],
76594
+ apply: "add",
76595
+ vocabularyCap: "power-meter",
76596
+ vocabularyStateField: "kwhTotal",
76597
+ sources: [{
76598
+ kind: "numeric",
76599
+ requiredUnit: "kWh",
76600
+ transformKinds: ["identity"],
76601
+ transforms: [{ kind: "identity" }]
76602
+ }],
76603
+ sourceReport: { status: "assignment-status" },
76604
+ advancedExpression: true,
76605
+ path: "kwhTotal",
76606
+ valueKind: "number",
76607
+ nullable: false,
76608
+ companions: [{
76609
+ kind: "clock",
76610
+ path: "lastFetchedAt",
76611
+ when: "always"
76612
+ }]
76613
+ },
76614
+ {
76615
+ id: "volts",
76616
+ cardinality: "scalar",
76617
+ deviceTypes: [
76618
+ DeviceType.Switch,
76619
+ DeviceType.Light,
76620
+ DeviceType.Fan,
76621
+ DeviceType.Climate,
76622
+ DeviceType.Thermostat,
76623
+ DeviceType.Humidifier,
76624
+ DeviceType.WaterHeater,
76625
+ DeviceType.MediaPlayer,
76626
+ DeviceType.Washer,
76627
+ DeviceType.Dryer,
76628
+ DeviceType.Dishwasher,
76629
+ DeviceType.Vacuum,
76630
+ DeviceType.LawnMower,
76631
+ DeviceType.PetFeeder
76632
+ ],
76633
+ apply: "add",
76634
+ vocabularyCap: "power-meter",
76635
+ vocabularyStateField: "volts",
76636
+ sources: [{
76637
+ kind: "numeric",
76638
+ requiredUnit: "V",
76639
+ transformKinds: ["identity"],
76640
+ transforms: [{ kind: "identity" }]
76641
+ }],
76642
+ sourceReport: { status: "assignment-status" },
76643
+ advancedExpression: true,
76644
+ path: "volts",
76645
+ valueKind: "number",
76646
+ nullable: false,
76647
+ companions: [{
76648
+ kind: "clock",
76649
+ path: "lastFetchedAt",
76650
+ when: "always"
76651
+ }]
76652
+ },
76653
+ {
76654
+ id: "amps",
76655
+ cardinality: "scalar",
76656
+ deviceTypes: [
76657
+ DeviceType.Switch,
76658
+ DeviceType.Light,
76659
+ DeviceType.Fan,
76660
+ DeviceType.Climate,
76661
+ DeviceType.Thermostat,
76662
+ DeviceType.Humidifier,
76663
+ DeviceType.WaterHeater,
76664
+ DeviceType.MediaPlayer,
76665
+ DeviceType.Washer,
76666
+ DeviceType.Dryer,
76667
+ DeviceType.Dishwasher,
76668
+ DeviceType.Vacuum,
76669
+ DeviceType.LawnMower,
76670
+ DeviceType.PetFeeder
76671
+ ],
76672
+ apply: "add",
76673
+ vocabularyCap: "power-meter",
76674
+ vocabularyStateField: "amps",
76675
+ sources: [{
76676
+ kind: "numeric",
76677
+ requiredUnit: "A",
76678
+ transformKinds: ["identity"],
76679
+ transforms: [{ kind: "identity" }]
76680
+ }],
76681
+ sourceReport: { status: "assignment-status" },
76682
+ advancedExpression: true,
76683
+ path: "amps",
76684
+ valueKind: "number",
76685
+ nullable: false,
76686
+ companions: [{
76687
+ kind: "clock",
76688
+ path: "lastFetchedAt",
76689
+ when: "always"
76690
+ }]
76691
+ }
76692
+ ]
75253
76693
  },
75254
76694
  "running-state": {
75255
76695
  version: 1,
@@ -75257,6 +76697,8 @@ var CAP_CUSTOMIZE_CATALOG = {
75257
76697
  id: "running",
75258
76698
  cardinality: "scalar",
75259
76699
  deviceTypes: [
76700
+ DeviceType.Washer,
76701
+ DeviceType.Dryer,
75260
76702
  DeviceType.Dishwasher,
75261
76703
  DeviceType.Vacuum,
75262
76704
  DeviceType.LawnMower,
@@ -75268,22 +76710,33 @@ var CAP_CUSTOMIZE_CATALOG = {
75268
76710
  DeviceType.Thermostat,
75269
76711
  DeviceType.PetFeeder
75270
76712
  ],
75271
- apply: "add-or-replace",
76713
+ apply: "add",
75272
76714
  vocabularyCap: "running-state",
75273
76715
  vocabularyStateField: "running",
75274
76716
  sources: [
75275
76717
  {
75276
76718
  kind: "switch",
75277
- transformKinds: ["identity"]
76719
+ transformKinds: ["identity"],
76720
+ transforms: [{ kind: "identity" }]
75278
76721
  },
75279
76722
  {
75280
76723
  kind: "binary",
75281
- transformKinds: ["identity", "invert"]
76724
+ transformKinds: ["identity", "invert"],
76725
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
75282
76726
  },
75283
76727
  {
75284
76728
  kind: "numeric",
75285
76729
  requiredUnit: "W",
75286
- transformKinds: ["threshold"]
76730
+ transformKinds: ["threshold"],
76731
+ transforms: [{
76732
+ kind: "threshold",
76733
+ comparisons: ["gte", "lte"],
76734
+ comparison: "gte",
76735
+ defaultThreshold: 5,
76736
+ defaultStartDwellMs: 3e4,
76737
+ defaultStopDwellMs: 18e4,
76738
+ thresholdUnit: "W"
76739
+ }]
75287
76740
  }
75288
76741
  ],
75289
76742
  sourceReport: {
@@ -75320,26 +76773,6 @@ var CAP_CUSTOMIZE_CATALOG = {
75320
76773
  sourceChangedAt: "prefer"
75321
76774
  }
75322
76775
  ]
75323
- }],
75324
- advancedParameters: []
75325
- },
75326
- "switch": {
75327
- version: 1,
75328
- targets: [],
75329
- advancedParameters: [{
75330
- path: "on",
75331
- kind: "boolean",
75332
- label: "On"
75333
- }]
75334
- },
75335
- "temperature-sensor": {
75336
- version: 1,
75337
- targets: [],
75338
- advancedParameters: [{
75339
- path: "celsius",
75340
- kind: "number",
75341
- label: "Temperature",
75342
- unit: "\xB0C"
75343
76776
  }]
75344
76777
  }
75345
76778
  };
@@ -75412,7 +76845,9 @@ var DEVICE_TYPE_CONTROL_KIND = {
75412
76845
  [DeviceType.Container]: "dummy",
75413
76846
  [DeviceType.Image]: "image",
75414
76847
  [DeviceType.PetFeeder]: "pet-feeder",
75415
- [DeviceType.Dishwasher]: "dishwasher"
76848
+ [DeviceType.Dishwasher]: "dishwasher",
76849
+ [DeviceType.Washer]: "dummy",
76850
+ [DeviceType.Dryer]: "dummy"
75416
76851
  };
75417
76852
  var DEVICE_TYPE_VALUES = new Set(Object.values(DeviceType));
75418
76853
  var METHOD_ACCESS_MAP = Object.freeze({
@@ -75521,6 +76956,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
75521
76956
  access: "view",
75522
76957
  role: "admin"
75523
76958
  },
76959
+ "addons.getPackageDocs": {
76960
+ capName: "addons",
76961
+ capScope: "system",
76962
+ addonId: null,
76963
+ access: "view",
76964
+ role: "admin"
76965
+ },
75524
76966
  "addons.getVersions": {
75525
76967
  capName: "addons",
75526
76968
  capScope: "system",
@@ -78629,6 +80071,27 @@ var METHOD_ACCESS_MAP = Object.freeze({
78629
80071
  access: "view",
78630
80072
  role: "viewer"
78631
80073
  },
80074
+ "groupActive.getStatus": {
80075
+ capName: "group-active",
80076
+ capScope: "device",
80077
+ addonId: null,
80078
+ access: "view",
80079
+ role: "viewer"
80080
+ },
80081
+ "groupCommands.getStatus": {
80082
+ capName: "group-commands",
80083
+ capScope: "device",
80084
+ addonId: null,
80085
+ access: "view",
80086
+ role: "viewer"
80087
+ },
80088
+ "groupStatus.getStatus": {
80089
+ capName: "group-status",
80090
+ capScope: "device",
80091
+ addonId: null,
80092
+ access: "view",
80093
+ role: "viewer"
80094
+ },
78632
80095
  "heatingValve.getStatus": {
78633
80096
  capName: "heating-valve",
78634
80097
  capScope: "device",
@@ -79581,6 +81044,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
79581
81044
  access: "create",
79582
81045
  role: "admin"
79583
81046
  },
81047
+ "meter.getStatus": {
81048
+ capName: "meter",
81049
+ capScope: "device",
81050
+ addonId: null,
81051
+ access: "view",
81052
+ role: "viewer"
81053
+ },
79584
81054
  "metricsProvider.collectSnapshot": {
79585
81055
  capName: "metrics-provider",
79586
81056
  capScope: "system",
@@ -87667,7 +89137,39 @@ var APPLIANCE_CAP_VOCABULARY = {
87667
89137
  phrase: t("When {device} finishes", "Quando {device} finisce"),
87668
89138
  icon: "square"
87669
89139
  }
87670
- }
89140
+ },
89141
+ overrides: { byType: {
89142
+ [DeviceType.Washer]: {
89143
+ state: { running: {
89144
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
89145
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
89146
+ } },
89147
+ events: {
89148
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
89149
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
89150
+ }
89151
+ },
89152
+ [DeviceType.Dryer]: {
89153
+ state: { running: {
89154
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
89155
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
89156
+ } },
89157
+ events: {
89158
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
89159
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
89160
+ }
89161
+ },
89162
+ [DeviceType.Dishwasher]: {
89163
+ state: { running: {
89164
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
89165
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
89166
+ } },
89167
+ events: {
89168
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
89169
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
89170
+ }
89171
+ }
89172
+ } }
87671
89173
  },
87672
89174
  update: {
87673
89175
  scope: "device",
@@ -88428,6 +89930,41 @@ var SENSOR_CAP_VOCABULARY = {
88428
89930
  icon: "flame"
88429
89931
  }]
88430
89932
  },
89933
+ "group-active": {
89934
+ scope: "device",
89935
+ noun: t("Group state", "Stato del gruppo")
89936
+ },
89937
+ "group-commands": {
89938
+ scope: "device",
89939
+ noun: t("Group command", "Comando di gruppo")
89940
+ },
89941
+ "group-status": {
89942
+ scope: "device",
89943
+ noun: t("Group", "Gruppo"),
89944
+ state: [
89945
+ {
89946
+ kind: "numeric",
89947
+ field: "included",
89948
+ quantity: t("the members reporting", "i membri che rispondono"),
89949
+ label: t("Reporting", "Rispondono"),
89950
+ icon: "users"
89951
+ },
89952
+ {
89953
+ kind: "numeric",
89954
+ field: "excluded",
89955
+ quantity: t("the members left out", "i membri esclusi"),
89956
+ label: t("Excluded", "Esclusi"),
89957
+ icon: "users"
89958
+ },
89959
+ {
89960
+ kind: "numeric",
89961
+ field: "total",
89962
+ quantity: t("the member count", "il numero di membri"),
89963
+ label: t("Members", "Membri"),
89964
+ icon: "sigma"
89965
+ }
89966
+ ]
89967
+ },
88431
89968
  "humidity-sensor": {
88432
89969
  scope: "device",
88433
89970
  noun: t("Humidity", "Umidit\xE0"),
@@ -88453,6 +89990,17 @@ var SENSOR_CAP_VOCABULARY = {
88453
89990
  }],
88454
89991
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
88455
89992
  },
89993
+ meter: {
89994
+ scope: "device",
89995
+ noun: t("Meter", "Contatore"),
89996
+ state: [{
89997
+ kind: "numeric",
89998
+ field: "value",
89999
+ quantity: t("the total", "il totale"),
90000
+ label: t("Total", "Totale"),
90001
+ icon: "gauge"
90002
+ }]
90003
+ },
88456
90004
  "numeric-sensor": {
88457
90005
  scope: "device",
88458
90006
  noun: t("Sensor", "Sensore"),
@@ -88461,7 +90009,6 @@ var SENSOR_CAP_VOCABULARY = {
88461
90009
  field: "value",
88462
90010
  quantity: t("the reading", "il valore"),
88463
90011
  label: t("Reading", "Valore"),
88464
- unitField: "unit",
88465
90012
  icon: "gauge"
88466
90013
  }]
88467
90014
  },
@@ -88597,7 +90144,7 @@ var SENSOR_CAP_VOCABULARY = {
88597
90144
  field: "temperature",
88598
90145
  quantity: t("the outdoor temperature", "la temperatura esterna"),
88599
90146
  label: t("Temperature", "Temperatura"),
88600
- unitField: "temperatureUnit",
90147
+ unit: "\xB0C",
88601
90148
  icon: "thermometer"
88602
90149
  },
88603
90150
  {
@@ -88613,7 +90160,7 @@ var SENSOR_CAP_VOCABULARY = {
88613
90160
  field: "windSpeed",
88614
90161
  quantity: t("the wind speed", "la velocit\xE0 del vento"),
88615
90162
  label: t("Wind", "Vento"),
88616
- unitField: "windSpeedUnit",
90163
+ unit: "m/s",
88617
90164
  icon: "wind"
88618
90165
  },
88619
90166
  {
@@ -88621,7 +90168,7 @@ var SENSOR_CAP_VOCABULARY = {
88621
90168
  field: "pressure",
88622
90169
  quantity: t("the air pressure", "la pressione atmosferica"),
88623
90170
  label: t("Pressure", "Pressione"),
88624
- unitField: "pressureUnit",
90171
+ unit: "hPa",
88625
90172
  icon: "gauge"
88626
90173
  }
88627
90174
  ]
@@ -88950,7 +90497,9 @@ var DEVICE_TYPE_DO_CAPS = {
88950
90497
  [DeviceType.Container]: [],
88951
90498
  [DeviceType.Image]: [],
88952
90499
  [DeviceType.PetFeeder]: ["pet-feeder"],
88953
- [DeviceType.Dishwasher]: ["dishwasher"]
90500
+ [DeviceType.Dishwasher]: ["dishwasher"],
90501
+ [DeviceType.Washer]: [],
90502
+ [DeviceType.Dryer]: []
88954
90503
  };
88955
90504
  var NUMERIC_ABOVE = t("When {quantity} of {device} rises above {threshold}", "Quando {quantity} di {device} sale sopra {threshold}");
88956
90505
  var NUMERIC_BELOW = t("When {quantity} of {device} falls below {threshold}", "Quando {quantity} di {device} scende sotto {threshold}");
@@ -88967,6 +90516,55 @@ var BATTERY_DEVICE_PROFILE = {
88967
90516
  },
88968
90517
  settings: {}
88969
90518
  };
90519
+ var PLUG_APPLIANCE_TYPES = [
90520
+ DeviceType.Washer,
90521
+ DeviceType.Dryer,
90522
+ DeviceType.Dishwasher
90523
+ ];
90524
+ var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
90525
+ var HOMEKIT_REASON = "HomeKit has no laundry-appliance service. The export tab would pair an accessory with nothing on it: running-state is withheld until a null reading can be unavailable, and power is not a HomeKit service this export honours.";
90526
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
90527
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
90528
+ var MATTER_REASON = "No Matter export is built. The closest device types are Laundry Washer (0x0073) and Laundry Dryer (0x0074); a power threshold is not the Laundry Washer Mode cluster.";
90529
+ function withheld(reason) {
90530
+ return {
90531
+ [DeviceType.Washer]: {
90532
+ exported: false,
90533
+ reason
90534
+ },
90535
+ [DeviceType.Dryer]: {
90536
+ exported: false,
90537
+ reason
90538
+ },
90539
+ [DeviceType.Dishwasher]: {
90540
+ exported: false,
90541
+ reason
90542
+ }
90543
+ };
90544
+ }
90545
+ function offered(received) {
90546
+ return {
90547
+ [DeviceType.Washer]: {
90548
+ exported: true,
90549
+ as: received
90550
+ },
90551
+ [DeviceType.Dryer]: {
90552
+ exported: true,
90553
+ as: received
90554
+ },
90555
+ [DeviceType.Dishwasher]: {
90556
+ exported: true,
90557
+ as: received
90558
+ }
90559
+ };
90560
+ }
90561
+ var APPLIANCE_EXPORT = {
90562
+ ha: offered(HA_AS),
90563
+ homekit: withheld(HOMEKIT_REASON),
90564
+ alexa: withheld(ALEXA_REASON),
90565
+ google: withheld(GOOGLE_REASON),
90566
+ matter: withheld(MATTER_REASON)
90567
+ };
88970
90568
  var OPERATOR_WRITTEN_STALE_MS = 10 * 6e4;
88971
90569
  var METHOD_DEVICE_SELECTORS = Object.freeze({
88972
90570
  "accessories.getStatus": [{
@@ -89934,6 +91532,21 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
89934
91532
  form: "single",
89935
91533
  optional: false
89936
91534
  }],
91535
+ "groupActive.getStatus": [{
91536
+ name: "deviceId",
91537
+ form: "single",
91538
+ optional: false
91539
+ }],
91540
+ "groupCommands.getStatus": [{
91541
+ name: "deviceId",
91542
+ form: "single",
91543
+ optional: false
91544
+ }],
91545
+ "groupStatus.getStatus": [{
91546
+ name: "deviceId",
91547
+ form: "single",
91548
+ optional: false
91549
+ }],
89937
91550
  "heatingValve.getStatus": [{
89938
91551
  name: "deviceId",
89939
91552
  form: "single",
@@ -90134,6 +91747,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
90134
91747
  form: "single",
90135
91748
  optional: false
90136
91749
  }],
91750
+ "meter.getStatus": [{
91751
+ name: "deviceId",
91752
+ form: "single",
91753
+ optional: false
91754
+ }],
90137
91755
  "motion.getStatus": [{
90138
91756
  name: "deviceId",
90139
91757
  form: "single",
@@ -91742,353 +93360,6 @@ var CAP_PROVIDER_KIND_MAP = Object.freeze({
91742
93360
  "smtp-provider": "email"
91743
93361
  });
91744
93362
  var HISTORY_BUCKET_MS = 5 * 6e4;
91745
- var HISTORY_CATALOG = {
91746
- "air-quality-sensor": {
91747
- "co2Ppm": {
91748
- kind: "gauge",
91749
- unit: "ppm",
91750
- deadband: 5
91751
- },
91752
- "vocPpb": {
91753
- kind: "gauge",
91754
- unit: "ppb",
91755
- deadband: 5
91756
- },
91757
- "pm25": {
91758
- kind: "gauge",
91759
- unit: "ug/m3",
91760
- deadband: 1
91761
- },
91762
- "pm10": {
91763
- kind: "gauge",
91764
- unit: "ug/m3",
91765
- deadband: 1
91766
- },
91767
- "aqi": {
91768
- kind: "gauge",
91769
- unit: "count",
91770
- deadband: 1
91771
- }
91772
- },
91773
- "alarm-panel": { "state": {
91774
- kind: "enum",
91775
- values: [
91776
- "disarmed",
91777
- "armed_home",
91778
- "armed_away",
91779
- "armed_night",
91780
- "armed_vacation",
91781
- "armed_custom_bypass",
91782
- "arming",
91783
- "disarming",
91784
- "pending",
91785
- "triggered"
91786
- ]
91787
- } },
91788
- "ambient-light-sensor": { "lux": {
91789
- kind: "gauge",
91790
- unit: "lx",
91791
- deadbandPct: 10,
91792
- minIntervalMs: 6e4
91793
- } },
91794
- "battery": { "percentage": {
91795
- kind: "gauge",
91796
- unit: "%"
91797
- } },
91798
- "binary": { "on": { kind: "boolean" } },
91799
- "brightness": { "percentage": {
91800
- kind: "gauge",
91801
- unit: "%",
91802
- minIntervalMs: 0
91803
- } },
91804
- "carbon-monoxide": { "detected": { kind: "boolean" } },
91805
- "climate-control": {
91806
- "currentTemp": {
91807
- kind: "gauge",
91808
- unit: "\xB0C",
91809
- deadband: 0.1
91810
- },
91811
- "currentHumidity": {
91812
- kind: "gauge",
91813
- unit: "%",
91814
- deadband: 0.5
91815
- },
91816
- "target": {
91817
- kind: "gauge",
91818
- unit: "\xB0C",
91819
- minIntervalMs: 0
91820
- },
91821
- "targetHigh": {
91822
- kind: "gauge",
91823
- unit: "\xB0C",
91824
- minIntervalMs: 0
91825
- },
91826
- "targetLow": {
91827
- kind: "gauge",
91828
- unit: "\xB0C",
91829
- minIntervalMs: 0
91830
- }
91831
- },
91832
- "connectivity": { "connected": { kind: "boolean" } },
91833
- "contact": { "entryOpen": { kind: "boolean" } },
91834
- "cover": { "position": {
91835
- kind: "gauge",
91836
- unit: "%",
91837
- minIntervalMs: 0
91838
- } },
91839
- "device-status": { "online": { kind: "boolean" } },
91840
- "dishwasher": {
91841
- "progressPercent": {
91842
- kind: "gauge",
91843
- unit: "%",
91844
- deadband: 2
91845
- },
91846
- "state": {
91847
- kind: "enum",
91848
- values: [
91849
- "idle",
91850
- "running",
91851
- "paused",
91852
- "finished",
91853
- "error",
91854
- "unavailable"
91855
- ]
91856
- },
91857
- "operationState": {
91858
- kind: "enum",
91859
- values: [
91860
- "Inactive",
91861
- "Ready",
91862
- "DelayedStart",
91863
- "Run",
91864
- "Pause",
91865
- "ActionRequired",
91866
- "Finished",
91867
- "Error",
91868
- "Aborting"
91869
- ]
91870
- },
91871
- "remainingSeconds": {
91872
- kind: "gauge",
91873
- unit: "s",
91874
- minIntervalMs: 6e4
91875
- },
91876
- "doorOpen": { kind: "boolean" },
91877
- "powerOn": { kind: "boolean" }
91878
- },
91879
- "enum-sensor": { "value": {
91880
- kind: "enum",
91881
- skipWhenSet: "format"
91882
- } },
91883
- "fan-control": {
91884
- "percentage": {
91885
- kind: "gauge",
91886
- unit: "%",
91887
- minIntervalMs: 0
91888
- },
91889
- "oscillating": { kind: "boolean" }
91890
- },
91891
- "flood": { "flooded": { kind: "boolean" } },
91892
- "gas": { "detected": { kind: "boolean" } },
91893
- "heating-valve": { "position": {
91894
- kind: "gauge",
91895
- unit: "%",
91896
- deadband: 1
91897
- } },
91898
- "humidifier": {
91899
- "currentHumidity": {
91900
- kind: "gauge",
91901
- unit: "%",
91902
- deadband: 0.5
91903
- },
91904
- "on": { kind: "boolean" }
91905
- },
91906
- "humidity-sensor": { "percent": {
91907
- kind: "gauge",
91908
- unit: "%",
91909
- deadband: 0.5
91910
- } },
91911
- "lawn-mower-control": { "batteryLevel": {
91912
- kind: "gauge",
91913
- unit: "%",
91914
- deadband: 2
91915
- } },
91916
- "lock-control": { "state": {
91917
- kind: "enum",
91918
- values: [
91919
- "locked",
91920
- "unlocked",
91921
- "locking",
91922
- "unlocking",
91923
- "jammed"
91924
- ]
91925
- } },
91926
- "media-player": {
91927
- "volumeLevel": {
91928
- kind: "gauge",
91929
- unit: "%",
91930
- deadband: 1
91931
- },
91932
- "isMuted": { kind: "boolean" }
91933
- },
91934
- "motion": { "detected": {
91935
- kind: "boolean",
91936
- excludeDeviceTypes: [DeviceType.Camera]
91937
- } },
91938
- "network-link": {
91939
- "signalPercent": {
91940
- kind: "gauge",
91941
- unit: "%",
91942
- deadband: 3,
91943
- minIntervalMs: 6e4
91944
- },
91945
- "rssiDbm": {
91946
- kind: "gauge",
91947
- unit: "dBm",
91948
- deadband: 2,
91949
- minIntervalMs: 6e4
91950
- }
91951
- },
91952
- "numeric-sensor": { "value": {
91953
- kind: "gauge",
91954
- unitFrom: "unit",
91955
- minIntervalMs: 3e4
91956
- } },
91957
- "pet-feeder": {
91958
- "foodLevel": { kind: "gauge" },
91959
- "food1": { kind: "gauge" },
91960
- "food2": { kind: "gauge" },
91961
- "batteryPower": {
91962
- kind: "gauge",
91963
- unit: "%",
91964
- deadband: 2
91965
- },
91966
- "desiccantLeftDays": {
91967
- kind: "gauge",
91968
- unit: "days"
91969
- }
91970
- },
91971
- "power-meter": {
91972
- "watts": {
91973
- kind: "gauge",
91974
- unit: "W",
91975
- deadband: 1,
91976
- minIntervalMs: 3e4
91977
- },
91978
- "kwhTotal": {
91979
- kind: "counter",
91980
- unit: "kWh",
91981
- deadband: 0.01,
91982
- minIntervalMs: 6e4
91983
- },
91984
- "volts": {
91985
- kind: "gauge",
91986
- unit: "V",
91987
- deadband: 1,
91988
- minIntervalMs: 3e4
91989
- },
91990
- "amps": {
91991
- kind: "gauge",
91992
- unit: "A",
91993
- deadband: 0.05,
91994
- minIntervalMs: 3e4
91995
- },
91996
- "va": {
91997
- kind: "gauge",
91998
- unit: "VA",
91999
- deadband: 1,
92000
- minIntervalMs: 3e4
92001
- },
92002
- "powerFactor": {
92003
- kind: "gauge",
92004
- unit: "ratio",
92005
- deadband: 0.01,
92006
- minIntervalMs: 6e4
92007
- }
92008
- },
92009
- "presence": { "batteryPercent": {
92010
- kind: "gauge",
92011
- unit: "%",
92012
- deadband: 1
92013
- } },
92014
- "pressure-sensor": { "hpa": {
92015
- kind: "gauge",
92016
- unit: "hPa",
92017
- deadband: 0.1
92018
- } },
92019
- "running-state": { "running": { kind: "boolean" } },
92020
- "smoke": { "detected": { kind: "boolean" } },
92021
- "stream-params": {
92022
- "main.bitrate": {
92023
- kind: "gauge",
92024
- unit: "kbps"
92025
- },
92026
- "main.framerate": {
92027
- kind: "gauge",
92028
- unit: "fps"
92029
- },
92030
- "sub.bitrate": {
92031
- kind: "gauge",
92032
- unit: "kbps"
92033
- },
92034
- "sub.framerate": {
92035
- kind: "gauge",
92036
- unit: "fps"
92037
- }
92038
- },
92039
- "switch": { "on": { kind: "boolean" } },
92040
- "tamper": { "tampered": { kind: "boolean" } },
92041
- "temperature-sensor": { "celsius": {
92042
- kind: "gauge",
92043
- unit: "\xB0C",
92044
- deadband: 0.1
92045
- } },
92046
- "vacuum-control": { "batteryLevel": {
92047
- kind: "gauge",
92048
- unit: "%",
92049
- deadband: 2
92050
- } },
92051
- "valve": { "position": {
92052
- kind: "gauge",
92053
- unit: "%",
92054
- minIntervalMs: 0
92055
- } },
92056
- "vibration": { "detected": { kind: "boolean" } },
92057
- "water-heater": {
92058
- "currentTemp": {
92059
- kind: "gauge",
92060
- unit: "\xB0C",
92061
- deadband: 0.5
92062
- },
92063
- "targetTemp": {
92064
- kind: "gauge",
92065
- unit: "\xB0C",
92066
- minIntervalMs: 0
92067
- }
92068
- },
92069
- "weather": {
92070
- "temperature": {
92071
- kind: "gauge",
92072
- unitFrom: "temperatureUnit",
92073
- deadband: 0.2
92074
- },
92075
- "humidity": {
92076
- kind: "gauge",
92077
- unit: "%",
92078
- deadband: 1
92079
- },
92080
- "pressure": {
92081
- kind: "gauge",
92082
- unitFrom: "pressureUnit",
92083
- deadband: 0.5
92084
- },
92085
- "windSpeed": {
92086
- kind: "gauge",
92087
- unitFrom: "windSpeedUnit",
92088
- deadband: 0.5
92089
- }
92090
- }
92091
- };
92092
93363
  var OverrideSourceSchema = external_exports.object({
92093
93364
  addonId: external_exports.string().min(1),
92094
93365
  stableId: external_exports.string().min(1),
@@ -92147,6 +93418,11 @@ var PulseOverrideDraftSchema = external_exports.object({
92147
93418
  targetId: external_exports.string().min(1),
92148
93419
  enabled: external_exports.boolean(),
92149
93420
  debounceMs: external_exports.number().nonnegative(),
93421
+ edges: external_exports.array(external_exports.enum([
93422
+ "rising",
93423
+ "button",
93424
+ "native-event"
93425
+ ])).min(1).optional(),
92150
93426
  sources: external_exports.array(OverrideSourceSchema).min(1)
92151
93427
  });
92152
93428
  var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: external_exports.enum([
@@ -92218,6 +93494,8 @@ var NC_SYSTEM_EVENT_FAMILY = {
92218
93494
  "detection-blind": "device-events",
92219
93495
  "motion-noisy": "device-events",
92220
93496
  "motion-calm": "device-events",
93497
+ "package-llm-silent": "device-events",
93498
+ "package-llm-answered": "device-events",
92221
93499
  "recording-stalled": "device-events",
92222
93500
  "recording-healthy": "device-events",
92223
93501
  "recording-degraded": "device-events",
@@ -92302,6 +93580,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
92302
93580
  label: "Motion without a subject",
92303
93581
  kinds: ["motion-noisy", "motion-calm"]
92304
93582
  },
93583
+ {
93584
+ id: "package-llm",
93585
+ family: "device-events",
93586
+ label: "Package confirm",
93587
+ kinds: ["package-llm-silent", "package-llm-answered"]
93588
+ },
92305
93589
  {
92306
93590
  id: "recording",
92307
93591
  family: "device-events",
@@ -92460,6 +93744,8 @@ var DEVICE_EVENTS = [
92460
93744
  "detection-blind",
92461
93745
  "motion-noisy",
92462
93746
  "motion-calm",
93747
+ "package-llm-silent",
93748
+ "package-llm-answered",
92463
93749
  "recording-stalled",
92464
93750
  "recording-healthy",
92465
93751
  "recording-degraded",
@@ -93060,7 +94346,8 @@ var NC_TEMPLATE_VARS = [
93060
94346
  systemEventKinds: [
93061
94347
  "recording-degraded",
93062
94348
  ...DEVICE_ATTENTION,
93063
- ...ALERT_EPISODE
94349
+ ...ALERT_EPISODE,
94350
+ "package-llm-silent"
93064
94351
  ]
93065
94352
  },
93066
94353
  {
@@ -93153,7 +94440,8 @@ var NC_TEMPLATE_VARS = [
93153
94440
  systemEventKinds: [
93154
94441
  "storage-location-low",
93155
94442
  "storage-location-critical",
93156
- "storage-location-ok"
94443
+ "storage-location-ok",
94444
+ "package-llm-silent"
93157
94445
  ]
93158
94446
  },
93159
94447
  {
@@ -93595,6 +94883,15 @@ var NC_SYSTEM_EVENT_CLASS_SPECS = [
93595
94883
  snapshotLabel: "Cameras with constant motion now",
93596
94884
  snapshotSection: null
93597
94885
  },
94886
+ {
94887
+ id: "package-llm-confirm",
94888
+ family: "device-events",
94889
+ label: "Package confirm (not answering / answering again)",
94890
+ bad: ["package-llm-silent"],
94891
+ recovery: ["package-llm-answered"],
94892
+ snapshotLabel: "Cameras whose package confirm is not answering",
94893
+ snapshotSection: null
94894
+ },
93598
94895
  {
93599
94896
  id: "recording-health",
93600
94897
  family: "device-events",
@@ -94063,6 +95360,24 @@ var NATIVE_LEASE_ADMISSION_FIELD = {
94063
95360
  }],
94064
95361
  default: DEFAULT_NATIVE_LEASE_SETTINGS.admission
94065
95362
  };
95363
+ var INFO_STEPS = [
95364
+ {
95365
+ factor: 1024 ** 4,
95366
+ unit: "TiB"
95367
+ },
95368
+ {
95369
+ factor: 1024 ** 3,
95370
+ unit: "GiB"
95371
+ },
95372
+ {
95373
+ factor: 1024 ** 2,
95374
+ unit: "MiB"
95375
+ },
95376
+ {
95377
+ factor: 1024,
95378
+ unit: "KiB"
95379
+ }
95380
+ ];
94066
95381
  var MB = 1024 * 1024;
94067
95382
  var DEFAULT_POOL_MEMORY_POLICY = {
94068
95383
  sampleIntervalMs: 6e4,