@camstack/addon-provider-homeassistant 1.2.628 → 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.
@@ -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",
@@ -10840,7 +10845,7 @@ object({
10840
10845
  params: record(string(), union([string(), number()])).optional()
10841
10846
  });
10842
10847
  //#endregion
10843
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10848
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10844
10849
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10845
10850
  DeviceType["Camera"] = "camera";
10846
10851
  DeviceType["Hub"] = "hub";
@@ -10934,8 +10939,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10934
10939
  DeviceType["PetFeeder"] = "pet-feeder";
10935
10940
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10936
10941
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10937
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10942
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10943
+ * A plug-built dishwasher carries running-state and power instead. */
10938
10944
  DeviceType["Dishwasher"] = "dishwasher";
10945
+ /** Washing machine. A plug-built one is running while its power stays
10946
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10947
+ DeviceType["Washer"] = "washer";
10948
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10949
+ DeviceType["Dryer"] = "dryer";
10939
10950
  return DeviceType;
10940
10951
  }({});
10941
10952
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -11193,7 +11204,7 @@ function errMsg(err) {
11193
11204
  return String(err);
11194
11205
  }
11195
11206
  //#endregion
11196
- //#region ../types/dist/composition-OhpuespA.mjs
11207
+ //#region ../types/dist/composition-CpETZ4HL.mjs
11197
11208
  /**
11198
11209
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11199
11210
  *
@@ -11949,6 +11960,97 @@ function validateExpressionSource(src) {
11949
11960
  return null;
11950
11961
  }
11951
11962
  /**
11963
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11964
+ *
11965
+ * Standby of the control board is under 5 W; a motor or a heater is far
11966
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11967
+ * a cycle, so running starts only after 30 s above the line.
11968
+ *
11969
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11970
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11971
+ * report "finished" in the middle of the program, so the stop dwell is
11972
+ * 10 minutes on every type. The number is stored per type so one machine
11973
+ * can move later without moving the others.
11974
+ */
11975
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11976
+ var APPLIANCE_KINDS = [
11977
+ "washer",
11978
+ "dryer",
11979
+ "dishwasher"
11980
+ ];
11981
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
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
+ /**
11952
12054
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11953
12055
  * id. Split out so helper schemas can name it without a cycle through
11954
12056
  * `composition.ts` (D659).
@@ -12004,14 +12106,37 @@ var HelperMemberSchema = object({
12004
12106
  cap: string().min(1),
12005
12107
  fieldPath: string().min(1)
12006
12108
  });
12007
- var HelperSpecSchema = discriminatedUnion("kind", [object({
12008
- kind: literal("group"),
12009
- templateId: GroupTemplateIdSchema,
12010
- aggregate: AggregateReducerSchema,
12011
- members: array(HelperMemberSchema).min(1).max(64),
12012
- /** Actuator groups only. Readings leave this unset. */
12013
- active: ActiveCriterionSchema.optional()
12014
- })]);
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
+ ]);
12015
12140
  /** A composed device's stableId is this prefix plus the block id. */
12016
12141
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12017
12142
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12085,6 +12210,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12085
12210
  "omit",
12086
12211
  "offline"
12087
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
+ ])
12088
12233
  })
12089
12234
  ]);
12090
12235
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18561,7 +18706,8 @@ var CompositionProblemSchema = object({
18561
18706
  "native-capability-replace",
18562
18707
  "mixed-quantity",
18563
18708
  "helper-mismatch",
18564
- "member-constraint"
18709
+ "member-constraint",
18710
+ "retention"
18565
18711
  ]),
18566
18712
  path: string(),
18567
18713
  message: string()
@@ -18801,7 +18947,7 @@ Object.freeze({
18801
18947
  * One catalog row per base reading a group helper can build (D944 §3).
18802
18948
  * Data, not a form default written into the block.
18803
18949
  */
18804
- var NOW = {
18950
+ var NOW$1 = {
18805
18951
  fieldPath: "lastFetchedAt",
18806
18952
  expr: "now"
18807
18953
  };
@@ -18847,7 +18993,7 @@ var GROUP_TEMPLATES = [
18847
18993
  quantity: "temperature",
18848
18994
  defaultAggregate: "mean",
18849
18995
  empty: "null",
18850
- companions: [NOW]
18996
+ companions: [NOW$1]
18851
18997
  }),
18852
18998
  numeric({
18853
18999
  id: "humidity",
@@ -18858,7 +19004,7 @@ var GROUP_TEMPLATES = [
18858
19004
  quantity: "humidity",
18859
19005
  defaultAggregate: "mean",
18860
19006
  empty: "null",
18861
- companions: [NOW]
19007
+ companions: [NOW$1]
18862
19008
  }),
18863
19009
  numeric({
18864
19010
  id: "pressure",
@@ -18869,7 +19015,7 @@ var GROUP_TEMPLATES = [
18869
19015
  quantity: "pressure",
18870
19016
  defaultAggregate: "mean",
18871
19017
  empty: "null",
18872
- companions: [NOW]
19018
+ companions: [NOW$1]
18873
19019
  }),
18874
19020
  numeric({
18875
19021
  id: "illuminance",
@@ -18880,7 +19026,7 @@ var GROUP_TEMPLATES = [
18880
19026
  quantity: "illuminance",
18881
19027
  defaultAggregate: "mean",
18882
19028
  empty: "null",
18883
- companions: [NOW]
19029
+ companions: [NOW$1]
18884
19030
  }),
18885
19031
  numeric({
18886
19032
  id: "power",
@@ -18891,7 +19037,7 @@ var GROUP_TEMPLATES = [
18891
19037
  quantity: "power",
18892
19038
  defaultAggregate: "sum",
18893
19039
  empty: "omit",
18894
- companions: [NOW]
19040
+ companions: [NOW$1]
18895
19041
  }),
18896
19042
  numeric({
18897
19043
  id: "energy",
@@ -18902,7 +19048,7 @@ var GROUP_TEMPLATES = [
18902
19048
  quantity: "energy",
18903
19049
  defaultAggregate: "sum",
18904
19050
  empty: "omit",
18905
- companions: [NOW]
19051
+ companions: [NOW$1]
18906
19052
  }),
18907
19053
  numeric({
18908
19054
  id: "battery",
@@ -18937,7 +19083,7 @@ var GROUP_TEMPLATES = [
18937
19083
  quantity: "device",
18938
19084
  defaultAggregate: "mean",
18939
19085
  empty: "null",
18940
- companions: [NOW]
19086
+ companions: [NOW$1]
18941
19087
  }),
18942
19088
  binary({
18943
19089
  id: "motion",
@@ -19066,6 +19212,7 @@ function actuator(input) {
19066
19212
  }
19067
19213
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19068
19214
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19215
+ DeviceType.Camera;
19069
19216
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19070
19217
  /**
19071
19218
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -62321,6 +62468,44 @@ var lockControlCapability = {
62321
62468
  volatileStateFields: ["lastChangedAt"]
62322
62469
  };
62323
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
+ /**
62324
62509
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
62325
62510
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
62326
62511
  * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
@@ -64847,7 +65032,12 @@ var powerMeterCapability = {
64847
65032
  scope: "device",
64848
65033
  deviceNative: true,
64849
65034
  mode: "singleton",
64850
- deviceTypes: [DeviceType.Sensor],
65035
+ deviceTypes: [
65036
+ DeviceType.Sensor,
65037
+ DeviceType.Washer,
65038
+ DeviceType.Dryer,
65039
+ DeviceType.Dishwasher
65040
+ ],
64851
65041
  methods: {},
64852
65042
  status: {
64853
65043
  schema: PowerMeterStatusSchema,
@@ -65593,6 +65783,8 @@ var runningCustomize = {
65593
65783
  stateField: "running"
65594
65784
  },
65595
65785
  deviceTypes: [
65786
+ DeviceType.Washer,
65787
+ DeviceType.Dryer,
65596
65788
  DeviceType.Dishwasher,
65597
65789
  DeviceType.Vacuum,
65598
65790
  DeviceType.LawnMower,
@@ -70731,7 +70923,7 @@ function tryConvertDelta(value, from, to) {
70731
70923
  return shifted - origin;
70732
70924
  }
70733
70925
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
70734
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
70926
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
70735
70927
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
70736
70928
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
70737
70929
  new Set(CAP_NAMES);
@@ -71071,6 +71263,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
71071
71263
  lawnMowerControl: lawnMowerControlCapability,
71072
71264
  lockControl: lockControlCapability,
71073
71265
  mediaPlayer: mediaPlayerCapability,
71266
+ meter: meterCapability,
71074
71267
  motion: motionCapability,
71075
71268
  motionTrigger: motionTriggerCapability,
71076
71269
  motionZones: motionZonesCapability,
@@ -72330,7 +72523,7 @@ var BaseDeviceProvider = class extends BaseAddon {
72330
72523
  return toDeviceSummary(device, this.addonId);
72331
72524
  }
72332
72525
  };
72333
- DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
72526
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
72334
72527
  new Set(Object.values(DeviceType));
72335
72528
  Object.freeze({
72336
72529
  "accessories.getStatus": {
@@ -76519,6 +76712,13 @@ Object.freeze({
76519
76712
  access: "create",
76520
76713
  role: "admin"
76521
76714
  },
76715
+ "meter.getStatus": {
76716
+ capName: "meter",
76717
+ capScope: "device",
76718
+ addonId: null,
76719
+ access: "view",
76720
+ role: "viewer"
76721
+ },
76522
76722
  "metricsProvider.collectSnapshot": {
76523
76723
  capName: "metrics-provider",
76524
76724
  capScope: "system",
@@ -84617,7 +84817,39 @@ var APPLIANCE_CAP_VOCABULARY = {
84617
84817
  phrase: t("When {device} finishes", "Quando {device} finisce"),
84618
84818
  icon: "square"
84619
84819
  }
84620
- }
84820
+ },
84821
+ overrides: { byType: {
84822
+ [DeviceType.Washer]: {
84823
+ state: { running: {
84824
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
84825
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
84826
+ } },
84827
+ events: {
84828
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
84829
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
84830
+ }
84831
+ },
84832
+ [DeviceType.Dryer]: {
84833
+ state: { running: {
84834
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
84835
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
84836
+ } },
84837
+ events: {
84838
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
84839
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
84840
+ }
84841
+ },
84842
+ [DeviceType.Dishwasher]: {
84843
+ state: { running: {
84844
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
84845
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
84846
+ } },
84847
+ events: {
84848
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
84849
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
84850
+ }
84851
+ }
84852
+ } }
84621
84853
  },
84622
84854
  update: {
84623
84855
  scope: "device",
@@ -85445,6 +85677,17 @@ var SENSOR_CAP_VOCABULARY = {
85445
85677
  }],
85446
85678
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
85447
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
+ },
85448
85691
  "numeric-sensor": {
85449
85692
  scope: "device",
85450
85693
  noun: t("Sensor", "Sensore"),
@@ -85917,8 +86160,58 @@ function projectAction(cap, action) {
85917
86160
  };
85918
86161
  }
85919
86162
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
85920
- DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
86163
+ DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
85921
86164
  DeviceFeature.BatteryOperated;
86165
+ /**
86166
+ * How a washer, dryer or dishwasher leaves CamStack.
86167
+ *
86168
+ * Home Assistant has no laundry domain: the device is offered, and what
86169
+ * travels is its power reading. The others have a laundry type that this
86170
+ * export cannot honour yet, so they are named and withheld.
86171
+ */
86172
+ var PLUG_APPLIANCE_TYPES = [
86173
+ DeviceType.Washer,
86174
+ DeviceType.Dryer,
86175
+ DeviceType.Dishwasher
86176
+ ];
86177
+ 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.";
86178
+ 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.";
86179
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
86180
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
86181
+ 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.";
86182
+ function withheld(reason) {
86183
+ return {
86184
+ [DeviceType.Washer]: {
86185
+ exported: false,
86186
+ reason
86187
+ },
86188
+ [DeviceType.Dryer]: {
86189
+ exported: false,
86190
+ reason
86191
+ },
86192
+ [DeviceType.Dishwasher]: {
86193
+ exported: false,
86194
+ reason
86195
+ }
86196
+ };
86197
+ }
86198
+ function offered(received) {
86199
+ return {
86200
+ [DeviceType.Washer]: {
86201
+ exported: true,
86202
+ as: received
86203
+ },
86204
+ [DeviceType.Dryer]: {
86205
+ exported: true,
86206
+ as: received
86207
+ },
86208
+ [DeviceType.Dishwasher]: {
86209
+ exported: true,
86210
+ as: received
86211
+ }
86212
+ };
86213
+ }
86214
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
85922
86215
  Object.freeze({
85923
86216
  "accessories.getStatus": [{
85924
86217
  name: "deviceId",
@@ -87095,6 +87388,11 @@ Object.freeze({
87095
87388
  form: "single",
87096
87389
  optional: false
87097
87390
  }],
87391
+ "meter.getStatus": [{
87392
+ name: "deviceId",
87393
+ form: "single",
87394
+ optional: false
87395
+ }],
87098
87396
  "motion.getStatus": [{
87099
87397
  name: "deviceId",
87100
87398
  form: "single",
@@ -88702,7 +89000,6 @@ Object.freeze({
88702
89000
  "network-access": "ingress",
88703
89001
  "smtp-provider": "email"
88704
89002
  });
88705
- DeviceType.Camera;
88706
89003
  /**
88707
89004
  * A saved Customize assignment (D936). The schema is the type: callers use
88708
89005
  * `z.infer`, they do not restate the shape.
@@ -90466,6 +90763,12 @@ Object.defineProperty(exports, "MediaPlayerRepeatSchema", {
90466
90763
  return MediaPlayerRepeatSchema;
90467
90764
  }
90468
90765
  });
90766
+ Object.defineProperty(exports, "PLUG_APPLIANCE_TYPES", {
90767
+ enumerable: true,
90768
+ get: function() {
90769
+ return PLUG_APPLIANCE_TYPES;
90770
+ }
90771
+ });
90469
90772
  Object.defineProperty(exports, "RUNNING_STATE_COLD", {
90470
90773
  enumerable: true,
90471
90774
  get: function() {
@@ -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-CAyJy-Ek.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."
@@ -6658,6 +6662,46 @@ function projectSynthetic(input, nowMs) {
6658
6662
  return values;
6659
6663
  }
6660
6664
  //#endregion
6665
+ //#region src/ha-export/supported-device-kinds.ts
6666
+ /**
6667
+ * Device types the Home Assistant export picker offers.
6668
+ *
6669
+ * A UI filter. What actually travels is still the entity catalog: a washer,
6670
+ * dryer or dishwasher is offered because its power reading exports as a
6671
+ * sensor. running-state stays unmapped.
6672
+ */
6673
+ var SUPPORTED_DEVICE_KINDS = [
6674
+ "camera",
6675
+ "light",
6676
+ "siren",
6677
+ "switch",
6678
+ "sensor",
6679
+ "thermostat",
6680
+ "climate",
6681
+ "button",
6682
+ "event-emitter",
6683
+ "update",
6684
+ "generic",
6685
+ "lock",
6686
+ "cover",
6687
+ "valve",
6688
+ "humidifier",
6689
+ "water-heater",
6690
+ "fan",
6691
+ "media-player",
6692
+ "alarm-panel",
6693
+ "control",
6694
+ "presence",
6695
+ "weather",
6696
+ "vacuum",
6697
+ "lawn-mower",
6698
+ "container",
6699
+ "image",
6700
+ "pet-feeder",
6701
+ "hub",
6702
+ ...require_dist.PLUG_APPLIANCE_TYPES
6703
+ ];
6704
+ //#endregion
6661
6705
  //#region src/ha-export/ha-export.addon.ts
6662
6706
  /**
6663
6707
  * Native Home Assistant export — a custom component fed by HTTP push.
@@ -9050,36 +9094,6 @@ var HaExportAddon = class extends require_dist.BaseAddon {
9050
9094
  * CAPABILITIES, not its type, and restricting the picker by type is what
9051
9095
  * confined the previous exporter to cameras.
9052
9096
  */
9053
- var SUPPORTED_DEVICE_KINDS = [
9054
- "camera",
9055
- "light",
9056
- "siren",
9057
- "switch",
9058
- "sensor",
9059
- "thermostat",
9060
- "climate",
9061
- "button",
9062
- "event-emitter",
9063
- "update",
9064
- "generic",
9065
- "lock",
9066
- "cover",
9067
- "valve",
9068
- "humidifier",
9069
- "water-heater",
9070
- "fan",
9071
- "media-player",
9072
- "alarm-panel",
9073
- "control",
9074
- "presence",
9075
- "weather",
9076
- "vacuum",
9077
- "lawn-mower",
9078
- "container",
9079
- "image",
9080
- "pet-feeder",
9081
- "hub"
9082
- ];
9083
9097
  /**
9084
9098
  * POST one message to Home Assistant's push view.
9085
9099
  *