@camstack/addon-provider-homeassistant 1.2.629 → 1.2.630

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-sQp4D2Eo.js");
2
+ const require_dist = require("./dist-Dcmr-Isu.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_zlib = require("node:zlib");
5
5
  //#region src/ha-admin-link.ts
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as lawnMowerControlCapability, $t as union, A as buttonCapability, At as weatherCapability, B as coverCapability, Bt as defineRecordKinds, C as batteryCapability, Ct as tryConvertDelta, D as brokerCapability, Dt as valveCapability, E as brightnessCapability, Et as vacuumControlCapability, F as connectivityCapability, G as eventEmitterCapability, Gt as array, H as deviceAdoptionCapability, It as RecordSecretUnavailableError, J as gasCapability, Jt as literal, K as fanControlCapability, Kt as boolean, Lt as baseUnitOf, M as carbonMonoxideCapability, Mt as DeviceRole, N as climateControlCapability, Nt as DeviceType, O as buildAddonRouteProvider, Ot as vibrationCapability, P as colorCapability, Pt as errMsg, Q as ingestReading, Qt as string, R as contactCapability, Rt as createEvent, S as automationControlCapability, St as temperatureSensorCapability, T as binaryCapability, Tt as updateCapability, V as deviceAdminLinkCapability, Vt as entryBody, W as enumSensorCapability, Wt as _enum, X as humiditySensorCapability, Xt as object, Y as humidifierCapability, Yt as number, Z as imageCapability, Zt as record, _ as accessoriesCapability, _t as runningStateCapability, at as notifierCapability, b as alarmPanelCapability, bt as switchCapability, ct as parseAdminBase, dt as presenceCapability, en as unknown, et as lockControlCapability, ft as pressureSensorCapability, g as TargetSchema, gt as runningFromVacuumState, h as RUNNING_STATE_COLD, ht as runningFromMediaPlayer, it as notificationOutputCapability, j as calendarSourceCapability, jt as DeviceFeature, k as buildDeviceAdminUrl, kt as waterHeaterCapability, lt as powerMeterCapability, mt as runningFromLawnMower, n as BaseDevice, nn as EventCategory, nt as motionCapability, ot as numericSensorCapability, pt as quantityFromUnit, q as floodCapability, qt as discriminatedUnion, r as BaseDeviceProvider, rt as normalizeUnit, tn as url, tt as mediaPlayerCapability, u as EnumSensorDateTimeFormatSchema, ut as prepareNotification, v as addonRoutesCapability, vt as scriptRunnerCapability, w as bestLocationMatch, wt as tryConvertUnit, x as ambientLightSensorCapability, xt as tamperCapability, y as airQualitySensorCapability, yt as smokeCapability, z as controlCapability, zt as defineEntryKind } from "./dist-DWMNvtWN.mjs";
1
+ import { $ as lawnMowerControlCapability, $t as union, A as buttonCapability, At as weatherCapability, B as coverCapability, Bt as defineRecordKinds, C as batteryCapability, Ct as tryConvertDelta, D as brokerCapability, Dt as valveCapability, E as brightnessCapability, Et as vacuumControlCapability, F as connectivityCapability, G as eventEmitterCapability, Gt as array, H as deviceAdoptionCapability, It as RecordSecretUnavailableError, J as gasCapability, Jt as literal, K as fanControlCapability, Kt as boolean, Lt as baseUnitOf, M as carbonMonoxideCapability, Mt as DeviceRole, N as climateControlCapability, Nt as DeviceType, O as buildAddonRouteProvider, Ot as vibrationCapability, P as colorCapability, Pt as errMsg, Q as ingestReading, Qt as string, R as contactCapability, Rt as createEvent, S as automationControlCapability, St as temperatureSensorCapability, T as binaryCapability, Tt as updateCapability, V as deviceAdminLinkCapability, Vt as entryBody, W as enumSensorCapability, Wt as _enum, X as humiditySensorCapability, Xt as object, Y as humidifierCapability, Yt as number, Z as imageCapability, Zt as record, _ as accessoriesCapability, _t as runningStateCapability, at as notifierCapability, b as alarmPanelCapability, bt as switchCapability, ct as parseAdminBase, dt as presenceCapability, en as unknown, et as lockControlCapability, ft as pressureSensorCapability, g as TargetSchema, gt as runningFromVacuumState, h as RUNNING_STATE_COLD, ht as runningFromMediaPlayer, it as notificationOutputCapability, j as calendarSourceCapability, jt as DeviceFeature, k as buildDeviceAdminUrl, kt as waterHeaterCapability, lt as powerMeterCapability, mt as runningFromLawnMower, n as BaseDevice, nn as EventCategory, nt as motionCapability, ot as numericSensorCapability, pt as quantityFromUnit, q as floodCapability, qt as discriminatedUnion, r as BaseDeviceProvider, rt as normalizeUnit, tn as url, tt as mediaPlayerCapability, u as EnumSensorDateTimeFormatSchema, ut as prepareNotification, v as addonRoutesCapability, vt as scriptRunnerCapability, w as bestLocationMatch, wt as tryConvertUnit, x as ambientLightSensorCapability, xt as tamperCapability, y as airQualitySensorCapability, yt as smokeCapability, z as controlCapability, zt as defineEntryKind } from "./dist-CT3sP-p0.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-admin-link.ts
@@ -5574,7 +5574,7 @@ var ZodIssueCode = {
5574
5574
  var ZodFirstPartyTypeKind;
5575
5575
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5576
5576
  //#endregion
5577
- //#region ../types/dist/sleep-bykKrTgu.mjs
5577
+ //#region ../types/dist/sleep-0sD_LHLI.mjs
5578
5578
  /**
5579
5579
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5580
5580
  * window to float samples (D455).
@@ -9039,6 +9039,7 @@ var CAP_NAMES = Object.freeze([
9039
9039
  "login-method",
9040
9040
  "media-player",
9041
9041
  "mesh-network",
9042
+ "meter",
9042
9043
  "metrics-provider",
9043
9044
  "model-convert",
9044
9045
  "model-distributor",
@@ -10096,6 +10097,10 @@ Object.freeze({
10096
10097
  ]
10097
10098
  }
10098
10099
  ],
10100
+ "meter": [{
10101
+ "path": "value",
10102
+ "valueType": "number"
10103
+ }],
10099
10104
  "motion": [
10100
10105
  {
10101
10106
  "path": "detected",
@@ -11198,7 +11203,7 @@ function errMsg(err) {
11198
11203
  return String(err);
11199
11204
  }
11200
11205
  //#endregion
11201
- //#region ../types/dist/composition-B2rw5L29.mjs
11206
+ //#region ../types/dist/composition-CpETZ4HL.mjs
11202
11207
  /**
11203
11208
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11204
11209
  *
@@ -11974,6 +11979,77 @@ var APPLIANCE_KINDS = [
11974
11979
  ];
11975
11980
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11976
11981
  /**
11982
+ * Statistics and integrals over a history read (D944).
11983
+ *
11984
+ * Pure: the same points always give the same answer, so a restart recomputes
11985
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11986
+ * never the mean of the samples. A hole with no held value is not integrated
11987
+ * as zero. A truncated read is not published.
11988
+ */
11989
+ var STATISTIC_STATS = [
11990
+ "min",
11991
+ "max",
11992
+ "mean",
11993
+ "sum",
11994
+ "count",
11995
+ "change"
11996
+ ];
11997
+ /**
11998
+ * The range a statistics or integral helper asks history for (D944).
11999
+ *
12000
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
12001
+ * or 25 hours across a DST change. A tier is eligible only when its retention
12002
+ * is strictly longer than the longest that range can be. Forever qualifies.
12003
+ * Equal to a tier's retention is a refusal, not a short answer.
12004
+ */
12005
+ var MINUTE_MS = 6e4;
12006
+ var HOUR_MS = 60 * MINUTE_MS;
12007
+ var DAY_MS = 24 * HOUR_MS;
12008
+ var ROLLING_SPANS = [
12009
+ "1h",
12010
+ "24h",
12011
+ "2d",
12012
+ "7d",
12013
+ "30d",
12014
+ "custom"
12015
+ ];
12016
+ var CALENDAR_PERIODS = [
12017
+ "today",
12018
+ "yesterday",
12019
+ "this-week",
12020
+ "this-month"
12021
+ ];
12022
+ var RESET_PERIODS = [
12023
+ "never",
12024
+ "daily",
12025
+ "weekly",
12026
+ "monthly"
12027
+ ];
12028
+ 5 * MINUTE_MS;
12029
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
12030
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
12031
+ var StatisticWindowSchema = discriminatedUnion("kind", [object({
12032
+ kind: literal("rolling"),
12033
+ span: _enum(ROLLING_SPANS),
12034
+ customMinutes: number().int().min(5).optional()
12035
+ }).check((payload) => {
12036
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12037
+ code: "custom",
12038
+ message: "a custom range needs a duration in minutes",
12039
+ path: ["customMinutes"],
12040
+ input: payload.value
12041
+ });
12042
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12043
+ code: "custom",
12044
+ message: "only a custom range carries a duration",
12045
+ path: ["customMinutes"],
12046
+ input: payload.value
12047
+ });
12048
+ }), object({
12049
+ kind: literal("calendar"),
12050
+ period: _enum(CALENDAR_PERIODS)
12051
+ })]);
12052
+ /**
11977
12053
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11978
12054
  * id. Split out so helper schemas can name it without a cycle through
11979
12055
  * `composition.ts` (D659).
@@ -12029,22 +12105,37 @@ var HelperMemberSchema = object({
12029
12105
  cap: string().min(1),
12030
12106
  fieldPath: string().min(1)
12031
12107
  });
12032
- var HelperSpecSchema = discriminatedUnion("kind", [object({
12033
- kind: literal("group"),
12034
- templateId: GroupTemplateIdSchema,
12035
- aggregate: AggregateReducerSchema,
12036
- members: array(HelperMemberSchema).min(1).max(64),
12037
- /** Actuator groups only. Readings leave this unset. */
12038
- active: ActiveCriterionSchema.optional()
12039
- }), object({
12040
- kind: literal("appliance"),
12041
- templateId: literal(APPLIANCE_TEMPLATE_ID),
12042
- appliance: _enum(APPLIANCE_KINDS),
12043
- thresholdWatts: number().positive(),
12044
- startDwellMs: number().int().nonnegative(),
12045
- stopDwellMs: number().int().nonnegative(),
12046
- member: HelperMemberSchema
12047
- })]);
12108
+ var HelperSpecSchema = discriminatedUnion("kind", [
12109
+ object({
12110
+ kind: literal("group"),
12111
+ templateId: GroupTemplateIdSchema,
12112
+ aggregate: AggregateReducerSchema,
12113
+ members: array(HelperMemberSchema).min(1).max(64),
12114
+ /** Actuator groups only. Readings leave this unset. */
12115
+ active: ActiveCriterionSchema.optional()
12116
+ }),
12117
+ object({
12118
+ kind: literal("appliance"),
12119
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12120
+ appliance: _enum(APPLIANCE_KINDS),
12121
+ thresholdWatts: number().positive(),
12122
+ startDwellMs: number().int().nonnegative(),
12123
+ stopDwellMs: number().int().nonnegative(),
12124
+ member: HelperMemberSchema
12125
+ }),
12126
+ object({
12127
+ kind: literal("statistic"),
12128
+ stat: _enum(STATISTIC_STATS),
12129
+ window: StatisticWindowSchema,
12130
+ source: HelperMemberSchema
12131
+ }),
12132
+ object({
12133
+ kind: literal("integral"),
12134
+ reset: _enum(RESET_PERIODS),
12135
+ output: _enum(["energy", "meter"]),
12136
+ source: HelperMemberSchema
12137
+ })
12138
+ ]);
12048
12139
  /** A composed device's stableId is this prefix plus the block id. */
12049
12140
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12050
12141
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12118,6 +12209,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12118
12209
  "omit",
12119
12210
  "offline"
12120
12211
  ])
12212
+ }),
12213
+ object({
12214
+ kind: literal("series"),
12215
+ read: CompositionFieldReadSchema,
12216
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12217
+ publish: _enum([
12218
+ "value",
12219
+ "included",
12220
+ "excluded",
12221
+ "total"
12222
+ ]),
12223
+ /**
12224
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12225
+ * device unseeded until history answers, so a restart cannot publish 0.
12226
+ */
12227
+ empty: _enum([
12228
+ "null",
12229
+ "omit",
12230
+ "offline"
12231
+ ])
12121
12232
  })
12122
12233
  ]);
12123
12234
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18594,7 +18705,8 @@ var CompositionProblemSchema = object({
18594
18705
  "native-capability-replace",
18595
18706
  "mixed-quantity",
18596
18707
  "helper-mismatch",
18597
- "member-constraint"
18708
+ "member-constraint",
18709
+ "retention"
18598
18710
  ]),
18599
18711
  path: string(),
18600
18712
  message: string()
@@ -18834,7 +18946,7 @@ Object.freeze({
18834
18946
  * One catalog row per base reading a group helper can build (D944 §3).
18835
18947
  * Data, not a form default written into the block.
18836
18948
  */
18837
- var NOW = {
18949
+ var NOW$1 = {
18838
18950
  fieldPath: "lastFetchedAt",
18839
18951
  expr: "now"
18840
18952
  };
@@ -18880,7 +18992,7 @@ var GROUP_TEMPLATES = [
18880
18992
  quantity: "temperature",
18881
18993
  defaultAggregate: "mean",
18882
18994
  empty: "null",
18883
- companions: [NOW]
18995
+ companions: [NOW$1]
18884
18996
  }),
18885
18997
  numeric({
18886
18998
  id: "humidity",
@@ -18891,7 +19003,7 @@ var GROUP_TEMPLATES = [
18891
19003
  quantity: "humidity",
18892
19004
  defaultAggregate: "mean",
18893
19005
  empty: "null",
18894
- companions: [NOW]
19006
+ companions: [NOW$1]
18895
19007
  }),
18896
19008
  numeric({
18897
19009
  id: "pressure",
@@ -18902,7 +19014,7 @@ var GROUP_TEMPLATES = [
18902
19014
  quantity: "pressure",
18903
19015
  defaultAggregate: "mean",
18904
19016
  empty: "null",
18905
- companions: [NOW]
19017
+ companions: [NOW$1]
18906
19018
  }),
18907
19019
  numeric({
18908
19020
  id: "illuminance",
@@ -18913,7 +19025,7 @@ var GROUP_TEMPLATES = [
18913
19025
  quantity: "illuminance",
18914
19026
  defaultAggregate: "mean",
18915
19027
  empty: "null",
18916
- companions: [NOW]
19028
+ companions: [NOW$1]
18917
19029
  }),
18918
19030
  numeric({
18919
19031
  id: "power",
@@ -18924,7 +19036,7 @@ var GROUP_TEMPLATES = [
18924
19036
  quantity: "power",
18925
19037
  defaultAggregate: "sum",
18926
19038
  empty: "omit",
18927
- companions: [NOW]
19039
+ companions: [NOW$1]
18928
19040
  }),
18929
19041
  numeric({
18930
19042
  id: "energy",
@@ -18935,7 +19047,7 @@ var GROUP_TEMPLATES = [
18935
19047
  quantity: "energy",
18936
19048
  defaultAggregate: "sum",
18937
19049
  empty: "omit",
18938
- companions: [NOW]
19050
+ companions: [NOW$1]
18939
19051
  }),
18940
19052
  numeric({
18941
19053
  id: "battery",
@@ -18970,7 +19082,7 @@ var GROUP_TEMPLATES = [
18970
19082
  quantity: "device",
18971
19083
  defaultAggregate: "mean",
18972
19084
  empty: "null",
18973
- companions: [NOW]
19085
+ companions: [NOW$1]
18974
19086
  }),
18975
19087
  binary({
18976
19088
  id: "motion",
@@ -19099,6 +19211,7 @@ function actuator(input) {
19099
19211
  }
19100
19212
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19101
19213
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19214
+ DeviceType.Camera;
19102
19215
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19103
19216
  /**
19104
19217
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -62354,6 +62467,44 @@ var lockControlCapability = {
62354
62467
  volatileStateFields: ["lastChangedAt"]
62355
62468
  };
62356
62469
  /**
62470
+ * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
62471
+ * so dashboards keep one series; every other instantaneous reading lands here.
62472
+ * `value` is the time integral in the source quantity's accumulated base
62473
+ * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
62474
+ */
62475
+ var MeterStatusSchema = object({
62476
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
62477
+ lastFetchedAt: number()
62478
+ });
62479
+ var meterCapability = {
62480
+ name: "meter",
62481
+ scope: "device",
62482
+ deviceNative: true,
62483
+ mode: "singleton",
62484
+ deviceTypes: [DeviceType.Sensor],
62485
+ methods: {},
62486
+ status: {
62487
+ schema: MeterStatusSchema,
62488
+ kind: "push"
62489
+ },
62490
+ runtimeState: MeterStatusSchema,
62491
+ /**
62492
+ * Runtime-state durability: **restored** — the total is a cache of the
62493
+ * history integral. A restart shows it only until the history pass
62494
+ * recomputes the open period; it is not an in-memory buffer.
62495
+ *
62496
+ * See `RuntimeStateDurability`. Enforced by
62497
+ * `scripts/check-runtime-state-durability.ts`.
62498
+ */
62499
+ durability: "restored",
62500
+ history: { fields: { value: {
62501
+ kind: "counter",
62502
+ deadband: .001,
62503
+ minIntervalMs: 6e4
62504
+ } } },
62505
+ volatileStateFields: ["lastFetchedAt"]
62506
+ };
62507
+ /**
62357
62508
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
62358
62509
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
62359
62510
  * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
@@ -71111,6 +71262,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
71111
71262
  lawnMowerControl: lawnMowerControlCapability,
71112
71263
  lockControl: lockControlCapability,
71113
71264
  mediaPlayer: mediaPlayerCapability,
71265
+ meter: meterCapability,
71114
71266
  motion: motionCapability,
71115
71267
  motionTrigger: motionTriggerCapability,
71116
71268
  motionZones: motionZonesCapability,
@@ -76559,6 +76711,13 @@ Object.freeze({
76559
76711
  access: "create",
76560
76712
  role: "admin"
76561
76713
  },
76714
+ "meter.getStatus": {
76715
+ capName: "meter",
76716
+ capScope: "device",
76717
+ addonId: null,
76718
+ access: "view",
76719
+ role: "viewer"
76720
+ },
76562
76721
  "metricsProvider.collectSnapshot": {
76563
76722
  capName: "metrics-provider",
76564
76723
  capScope: "system",
@@ -85517,6 +85676,17 @@ var SENSOR_CAP_VOCABULARY = {
85517
85676
  }],
85518
85677
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
85519
85678
  },
85679
+ meter: {
85680
+ scope: "device",
85681
+ noun: t("Meter", "Contatore"),
85682
+ state: [{
85683
+ kind: "numeric",
85684
+ field: "value",
85685
+ quantity: t("the total", "il totale"),
85686
+ label: t("Total", "Totale"),
85687
+ icon: "gauge"
85688
+ }]
85689
+ },
85520
85690
  "numeric-sensor": {
85521
85691
  scope: "device",
85522
85692
  noun: t("Sensor", "Sensore"),
@@ -87217,6 +87387,11 @@ Object.freeze({
87217
87387
  form: "single",
87218
87388
  optional: false
87219
87389
  }],
87390
+ "meter.getStatus": [{
87391
+ name: "deviceId",
87392
+ form: "single",
87393
+ optional: false
87394
+ }],
87220
87395
  "motion.getStatus": [{
87221
87396
  name: "deviceId",
87222
87397
  form: "single",
@@ -88824,7 +88999,6 @@ Object.freeze({
88824
88999
  "network-access": "ingress",
88825
89000
  "smtp-provider": "email"
88826
89001
  });
88827
- DeviceType.Camera;
88828
89002
  /**
88829
89003
  * A saved Customize assignment (D936). The schema is the type: callers use
88830
89004
  * `z.infer`, they do not restate the shape.
@@ -5575,7 +5575,7 @@ var ZodIssueCode = {
5575
5575
  var ZodFirstPartyTypeKind;
5576
5576
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5577
5577
  //#endregion
5578
- //#region ../types/dist/sleep-bykKrTgu.mjs
5578
+ //#region ../types/dist/sleep-0sD_LHLI.mjs
5579
5579
  /**
5580
5580
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5581
5581
  * window to float samples (D455).
@@ -9040,6 +9040,7 @@ var CAP_NAMES = Object.freeze([
9040
9040
  "login-method",
9041
9041
  "media-player",
9042
9042
  "mesh-network",
9043
+ "meter",
9043
9044
  "metrics-provider",
9044
9045
  "model-convert",
9045
9046
  "model-distributor",
@@ -10097,6 +10098,10 @@ Object.freeze({
10097
10098
  ]
10098
10099
  }
10099
10100
  ],
10101
+ "meter": [{
10102
+ "path": "value",
10103
+ "valueType": "number"
10104
+ }],
10100
10105
  "motion": [
10101
10106
  {
10102
10107
  "path": "detected",
@@ -11199,7 +11204,7 @@ function errMsg(err) {
11199
11204
  return String(err);
11200
11205
  }
11201
11206
  //#endregion
11202
- //#region ../types/dist/composition-B2rw5L29.mjs
11207
+ //#region ../types/dist/composition-CpETZ4HL.mjs
11203
11208
  /**
11204
11209
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11205
11210
  *
@@ -11975,6 +11980,77 @@ var APPLIANCE_KINDS = [
11975
11980
  ];
11976
11981
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11977
11982
  /**
11983
+ * Statistics and integrals over a history read (D944).
11984
+ *
11985
+ * Pure: the same points always give the same answer, so a restart recomputes
11986
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11987
+ * never the mean of the samples. A hole with no held value is not integrated
11988
+ * as zero. A truncated read is not published.
11989
+ */
11990
+ var STATISTIC_STATS = [
11991
+ "min",
11992
+ "max",
11993
+ "mean",
11994
+ "sum",
11995
+ "count",
11996
+ "change"
11997
+ ];
11998
+ /**
11999
+ * The range a statistics or integral helper asks history for (D944).
12000
+ *
12001
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
12002
+ * or 25 hours across a DST change. A tier is eligible only when its retention
12003
+ * is strictly longer than the longest that range can be. Forever qualifies.
12004
+ * Equal to a tier's retention is a refusal, not a short answer.
12005
+ */
12006
+ var MINUTE_MS = 6e4;
12007
+ var HOUR_MS = 60 * MINUTE_MS;
12008
+ var DAY_MS = 24 * HOUR_MS;
12009
+ var ROLLING_SPANS = [
12010
+ "1h",
12011
+ "24h",
12012
+ "2d",
12013
+ "7d",
12014
+ "30d",
12015
+ "custom"
12016
+ ];
12017
+ var CALENDAR_PERIODS = [
12018
+ "today",
12019
+ "yesterday",
12020
+ "this-week",
12021
+ "this-month"
12022
+ ];
12023
+ var RESET_PERIODS = [
12024
+ "never",
12025
+ "daily",
12026
+ "weekly",
12027
+ "monthly"
12028
+ ];
12029
+ 5 * MINUTE_MS;
12030
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
12031
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
12032
+ var StatisticWindowSchema = discriminatedUnion("kind", [object({
12033
+ kind: literal("rolling"),
12034
+ span: _enum(ROLLING_SPANS),
12035
+ customMinutes: number().int().min(5).optional()
12036
+ }).check((payload) => {
12037
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12038
+ code: "custom",
12039
+ message: "a custom range needs a duration in minutes",
12040
+ path: ["customMinutes"],
12041
+ input: payload.value
12042
+ });
12043
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12044
+ code: "custom",
12045
+ message: "only a custom range carries a duration",
12046
+ path: ["customMinutes"],
12047
+ input: payload.value
12048
+ });
12049
+ }), object({
12050
+ kind: literal("calendar"),
12051
+ period: _enum(CALENDAR_PERIODS)
12052
+ })]);
12053
+ /**
11978
12054
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11979
12055
  * id. Split out so helper schemas can name it without a cycle through
11980
12056
  * `composition.ts` (D659).
@@ -12030,22 +12106,37 @@ var HelperMemberSchema = object({
12030
12106
  cap: string().min(1),
12031
12107
  fieldPath: string().min(1)
12032
12108
  });
12033
- var HelperSpecSchema = discriminatedUnion("kind", [object({
12034
- kind: literal("group"),
12035
- templateId: GroupTemplateIdSchema,
12036
- aggregate: AggregateReducerSchema,
12037
- members: array(HelperMemberSchema).min(1).max(64),
12038
- /** Actuator groups only. Readings leave this unset. */
12039
- active: ActiveCriterionSchema.optional()
12040
- }), object({
12041
- kind: literal("appliance"),
12042
- templateId: literal(APPLIANCE_TEMPLATE_ID),
12043
- appliance: _enum(APPLIANCE_KINDS),
12044
- thresholdWatts: number().positive(),
12045
- startDwellMs: number().int().nonnegative(),
12046
- stopDwellMs: number().int().nonnegative(),
12047
- member: HelperMemberSchema
12048
- })]);
12109
+ var HelperSpecSchema = discriminatedUnion("kind", [
12110
+ object({
12111
+ kind: literal("group"),
12112
+ templateId: GroupTemplateIdSchema,
12113
+ aggregate: AggregateReducerSchema,
12114
+ members: array(HelperMemberSchema).min(1).max(64),
12115
+ /** Actuator groups only. Readings leave this unset. */
12116
+ active: ActiveCriterionSchema.optional()
12117
+ }),
12118
+ object({
12119
+ kind: literal("appliance"),
12120
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12121
+ appliance: _enum(APPLIANCE_KINDS),
12122
+ thresholdWatts: number().positive(),
12123
+ startDwellMs: number().int().nonnegative(),
12124
+ stopDwellMs: number().int().nonnegative(),
12125
+ member: HelperMemberSchema
12126
+ }),
12127
+ object({
12128
+ kind: literal("statistic"),
12129
+ stat: _enum(STATISTIC_STATS),
12130
+ window: StatisticWindowSchema,
12131
+ source: HelperMemberSchema
12132
+ }),
12133
+ object({
12134
+ kind: literal("integral"),
12135
+ reset: _enum(RESET_PERIODS),
12136
+ output: _enum(["energy", "meter"]),
12137
+ source: HelperMemberSchema
12138
+ })
12139
+ ]);
12049
12140
  /** A composed device's stableId is this prefix plus the block id. */
12050
12141
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12051
12142
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12119,6 +12210,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12119
12210
  "omit",
12120
12211
  "offline"
12121
12212
  ])
12213
+ }),
12214
+ object({
12215
+ kind: literal("series"),
12216
+ read: CompositionFieldReadSchema,
12217
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12218
+ publish: _enum([
12219
+ "value",
12220
+ "included",
12221
+ "excluded",
12222
+ "total"
12223
+ ]),
12224
+ /**
12225
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12226
+ * device unseeded until history answers, so a restart cannot publish 0.
12227
+ */
12228
+ empty: _enum([
12229
+ "null",
12230
+ "omit",
12231
+ "offline"
12232
+ ])
12122
12233
  })
12123
12234
  ]);
12124
12235
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18595,7 +18706,8 @@ var CompositionProblemSchema = object({
18595
18706
  "native-capability-replace",
18596
18707
  "mixed-quantity",
18597
18708
  "helper-mismatch",
18598
- "member-constraint"
18709
+ "member-constraint",
18710
+ "retention"
18599
18711
  ]),
18600
18712
  path: string(),
18601
18713
  message: string()
@@ -18835,7 +18947,7 @@ Object.freeze({
18835
18947
  * One catalog row per base reading a group helper can build (D944 §3).
18836
18948
  * Data, not a form default written into the block.
18837
18949
  */
18838
- var NOW = {
18950
+ var NOW$1 = {
18839
18951
  fieldPath: "lastFetchedAt",
18840
18952
  expr: "now"
18841
18953
  };
@@ -18881,7 +18993,7 @@ var GROUP_TEMPLATES = [
18881
18993
  quantity: "temperature",
18882
18994
  defaultAggregate: "mean",
18883
18995
  empty: "null",
18884
- companions: [NOW]
18996
+ companions: [NOW$1]
18885
18997
  }),
18886
18998
  numeric({
18887
18999
  id: "humidity",
@@ -18892,7 +19004,7 @@ var GROUP_TEMPLATES = [
18892
19004
  quantity: "humidity",
18893
19005
  defaultAggregate: "mean",
18894
19006
  empty: "null",
18895
- companions: [NOW]
19007
+ companions: [NOW$1]
18896
19008
  }),
18897
19009
  numeric({
18898
19010
  id: "pressure",
@@ -18903,7 +19015,7 @@ var GROUP_TEMPLATES = [
18903
19015
  quantity: "pressure",
18904
19016
  defaultAggregate: "mean",
18905
19017
  empty: "null",
18906
- companions: [NOW]
19018
+ companions: [NOW$1]
18907
19019
  }),
18908
19020
  numeric({
18909
19021
  id: "illuminance",
@@ -18914,7 +19026,7 @@ var GROUP_TEMPLATES = [
18914
19026
  quantity: "illuminance",
18915
19027
  defaultAggregate: "mean",
18916
19028
  empty: "null",
18917
- companions: [NOW]
19029
+ companions: [NOW$1]
18918
19030
  }),
18919
19031
  numeric({
18920
19032
  id: "power",
@@ -18925,7 +19037,7 @@ var GROUP_TEMPLATES = [
18925
19037
  quantity: "power",
18926
19038
  defaultAggregate: "sum",
18927
19039
  empty: "omit",
18928
- companions: [NOW]
19040
+ companions: [NOW$1]
18929
19041
  }),
18930
19042
  numeric({
18931
19043
  id: "energy",
@@ -18936,7 +19048,7 @@ var GROUP_TEMPLATES = [
18936
19048
  quantity: "energy",
18937
19049
  defaultAggregate: "sum",
18938
19050
  empty: "omit",
18939
- companions: [NOW]
19051
+ companions: [NOW$1]
18940
19052
  }),
18941
19053
  numeric({
18942
19054
  id: "battery",
@@ -18971,7 +19083,7 @@ var GROUP_TEMPLATES = [
18971
19083
  quantity: "device",
18972
19084
  defaultAggregate: "mean",
18973
19085
  empty: "null",
18974
- companions: [NOW]
19086
+ companions: [NOW$1]
18975
19087
  }),
18976
19088
  binary({
18977
19089
  id: "motion",
@@ -19100,6 +19212,7 @@ function actuator(input) {
19100
19212
  }
19101
19213
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19102
19214
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19215
+ DeviceType.Camera;
19103
19216
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19104
19217
  /**
19105
19218
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -62355,6 +62468,44 @@ var lockControlCapability = {
62355
62468
  volatileStateFields: ["lastChangedAt"]
62356
62469
  };
62357
62470
  /**
62471
+ * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
62472
+ * so dashboards keep one series; every other instantaneous reading lands here.
62473
+ * `value` is the time integral in the source quantity's accumulated base
62474
+ * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
62475
+ */
62476
+ var MeterStatusSchema = object({
62477
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
62478
+ lastFetchedAt: number()
62479
+ });
62480
+ var meterCapability = {
62481
+ name: "meter",
62482
+ scope: "device",
62483
+ deviceNative: true,
62484
+ mode: "singleton",
62485
+ deviceTypes: [DeviceType.Sensor],
62486
+ methods: {},
62487
+ status: {
62488
+ schema: MeterStatusSchema,
62489
+ kind: "push"
62490
+ },
62491
+ runtimeState: MeterStatusSchema,
62492
+ /**
62493
+ * Runtime-state durability: **restored** — the total is a cache of the
62494
+ * history integral. A restart shows it only until the history pass
62495
+ * recomputes the open period; it is not an in-memory buffer.
62496
+ *
62497
+ * See `RuntimeStateDurability`. Enforced by
62498
+ * `scripts/check-runtime-state-durability.ts`.
62499
+ */
62500
+ durability: "restored",
62501
+ history: { fields: { value: {
62502
+ kind: "counter",
62503
+ deadband: .001,
62504
+ minIntervalMs: 6e4
62505
+ } } },
62506
+ volatileStateFields: ["lastFetchedAt"]
62507
+ };
62508
+ /**
62358
62509
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
62359
62510
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
62360
62511
  * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
@@ -71112,6 +71263,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
71112
71263
  lawnMowerControl: lawnMowerControlCapability,
71113
71264
  lockControl: lockControlCapability,
71114
71265
  mediaPlayer: mediaPlayerCapability,
71266
+ meter: meterCapability,
71115
71267
  motion: motionCapability,
71116
71268
  motionTrigger: motionTriggerCapability,
71117
71269
  motionZones: motionZonesCapability,
@@ -76560,6 +76712,13 @@ Object.freeze({
76560
76712
  access: "create",
76561
76713
  role: "admin"
76562
76714
  },
76715
+ "meter.getStatus": {
76716
+ capName: "meter",
76717
+ capScope: "device",
76718
+ addonId: null,
76719
+ access: "view",
76720
+ role: "viewer"
76721
+ },
76563
76722
  "metricsProvider.collectSnapshot": {
76564
76723
  capName: "metrics-provider",
76565
76724
  capScope: "system",
@@ -85518,6 +85677,17 @@ var SENSOR_CAP_VOCABULARY = {
85518
85677
  }],
85519
85678
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
85520
85679
  },
85680
+ meter: {
85681
+ scope: "device",
85682
+ noun: t("Meter", "Contatore"),
85683
+ state: [{
85684
+ kind: "numeric",
85685
+ field: "value",
85686
+ quantity: t("the total", "il totale"),
85687
+ label: t("Total", "Totale"),
85688
+ icon: "gauge"
85689
+ }]
85690
+ },
85521
85691
  "numeric-sensor": {
85522
85692
  scope: "device",
85523
85693
  noun: t("Sensor", "Sensore"),
@@ -87218,6 +87388,11 @@ Object.freeze({
87218
87388
  form: "single",
87219
87389
  optional: false
87220
87390
  }],
87391
+ "meter.getStatus": [{
87392
+ name: "deviceId",
87393
+ form: "single",
87394
+ optional: false
87395
+ }],
87221
87396
  "motion.getStatus": [{
87222
87397
  name: "deviceId",
87223
87398
  form: "single",
@@ -88825,7 +89000,6 @@ Object.freeze({
88825
89000
  "network-access": "ingress",
88826
89001
  "smtp-provider": "email"
88827
89002
  });
88828
- DeviceType.Camera;
88829
89003
  /**
88830
89004
  * A saved Customize assignment (D936). The schema is the type: callers use
88831
89005
  * `z.infer`, they do not restate the shape.
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-sQp4D2Eo.js");
27
+ const require_dist = require("../dist-Dcmr-Isu.js");
28
28
  let node_crypto = require("node:crypto");
29
29
  require("node:zlib");
30
30
  let node_fs = require("node:fs");
@@ -3492,6 +3492,10 @@ var CAPS_NOT_EXPORTED = [
3492
3492
  cap: "group-status",
3493
3493
  reason: "Bookkeeping for a helper group (D944): how many members were included, excluded, or named. The value an operator automates on is the output capability (the temperature, the motion, the watts). These counts are session-only, have no history, and would publish a second entity that never means the reading."
3494
3494
  },
3495
+ {
3496
+ cap: "meter",
3497
+ reason: "The integral of a gauge that is not watts (D944). The total is base-unit seconds between resets; energy from watts is power-meter.kwhTotal. The source quantity is not on this device yet, so publishing the total as a sensor would give it no unit."
3498
+ },
3495
3499
  {
3496
3500
  cap: "group-commands",
3497
3501
  reason: "The last fan-out a helper group attempted (D944), one row per member. It is session-only and has no history. The command an automation sends is the member capability (switch, brightness, colour), not this record."
@@ -1,4 +1,4 @@
1
- import { Ft as BaseAddon, Gt as array, Ht as isReadingQuantity, I as consumableFormOf, L as consumableKindOf, Lt as baseUnitOf, O as buildAddonRouteProvider, Qt as string, U as deviceExportCapability, Ut as nodePin, Xt as object, a as COCO_TO_MACRO, c as ConsumableItemSchema, d as FanDirectionSchema, en as unknown, f as HvacModeSchema, i as CAMERA_SWITCH_ORDER, l as ConsumableStatusSchema, m as PLUG_APPLIANCE_TYPES, nn as EventCategory, o as CameraSwitchIdSchema, p as MediaPlayerRepeatSchema, s as ConsumableFormSchema, st as oauthIntegrationCapability, t as AlarmArmModeSchema, v as addonRoutesCapability } from "../dist-DWMNvtWN.mjs";
1
+ import { Ft as BaseAddon, Gt as array, Ht as isReadingQuantity, I as consumableFormOf, L as consumableKindOf, Lt as baseUnitOf, O as buildAddonRouteProvider, Qt as string, U as deviceExportCapability, Ut as nodePin, Xt as object, a as COCO_TO_MACRO, c as ConsumableItemSchema, d as FanDirectionSchema, en as unknown, f as HvacModeSchema, i as CAMERA_SWITCH_ORDER, l as ConsumableStatusSchema, m as PLUG_APPLIANCE_TYPES, nn as EventCategory, o as CameraSwitchIdSchema, p as MediaPlayerRepeatSchema, s as ConsumableFormSchema, st as oauthIntegrationCapability, t as AlarmArmModeSchema, v as addonRoutesCapability } from "../dist-CT3sP-p0.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  import "node:zlib";
4
4
  import "node:fs";
@@ -3457,6 +3457,10 @@ var CAPS_NOT_EXPORTED = [
3457
3457
  cap: "group-status",
3458
3458
  reason: "Bookkeeping for a helper group (D944): how many members were included, excluded, or named. The value an operator automates on is the output capability (the temperature, the motion, the watts). These counts are session-only, have no history, and would publish a second entity that never means the reading."
3459
3459
  },
3460
+ {
3461
+ cap: "meter",
3462
+ reason: "The integral of a gauge that is not watts (D944). The total is base-unit seconds between resets; energy from watts is power-meter.kwhTotal. The source quantity is not on this device yet, so publishing the total as a sensor would give it no unit."
3463
+ },
3460
3464
  {
3461
3465
  cap: "group-commands",
3462
3466
  reason: "The last fan-out a helper group attempted (D944), one row per member. It is session-only and has no history. The command an automation sends is the member capability (switch, brightness, colour), not this record."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.629",
3
+ "version": "1.2.630",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",