@camstack/addon-post-analysis 1.2.658 → 1.2.660

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/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.660] - 2026-11-01
11
+
12
+ ### Changed
13
+
14
+ - Rebuilt against updated dependencies.
15
+
16
+ ## [1.2.659] - 2026-11-01
17
+
18
+ ### Changed
19
+
20
+ - Notification rules fire once per appliance start/finish (running-state flip), not on every status refresh
21
+
10
22
  ## [1.2.658] - 2026-11-01
11
23
 
12
24
  ### Changed
@@ -11832,7 +11832,7 @@ function sleep(ms) {
11832
11832
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
11833
11833
  }
11834
11834
  //#endregion
11835
- //#region ../types/dist/composition-BBzVf2xd.mjs
11835
+ //#region ../types/dist/composition-BiKWlUCc.mjs
11836
11836
  /**
11837
11837
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
11838
11838
  * canonical form sorts object keys alphabetically at every depth so two
@@ -12925,7 +12925,15 @@ var HelperSpecSchema = discriminatedUnion("kind", [
12925
12925
  thresholdWatts: number().positive(),
12926
12926
  startDwellMs: number().int().nonnegative(),
12927
12927
  stopDwellMs: number().int().nonnegative(),
12928
- member: HelperMemberSchema
12928
+ member: HelperMemberSchema,
12929
+ /**
12930
+ * The plug that powers the appliance (`switch.on`). Optional: when set, the
12931
+ * composition carries a `power-source` feature, so the hub can cut and restore
12932
+ * that plug (power-source link of a NEW-target composition).
12933
+ */
12934
+ powerSwitch: HelperMemberSchema.optional(),
12935
+ /** How long a forced restart keeps the plug off; the cap's default when unset. */
12936
+ offSeconds: number().optional()
12929
12937
  }),
12930
12938
  object({
12931
12939
  kind: literal("statistic"),
@@ -47717,6 +47725,117 @@ function actuator(input) {
47717
47725
  };
47718
47726
  }
47719
47727
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
47728
+ var PowerSourceRefusalReasonSchema = _enum([
47729
+ "no-power-source",
47730
+ "switch-missing",
47731
+ "switch-offline",
47732
+ "switch-unknown",
47733
+ "restart-in-progress",
47734
+ "switch-call-failed"
47735
+ ]);
47736
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
47737
+ accepted: literal(false),
47738
+ reason: PowerSourceRefusalReasonSchema,
47739
+ /** One line for the operator, naming the switch. */
47740
+ message: string()
47741
+ })]);
47742
+ var PowerSourceInfoSchema = object({
47743
+ /** False when the device has no power source linked; the rest is then empty. */
47744
+ linked: boolean(),
47745
+ switchDeviceId: number().nullable(),
47746
+ switchName: string().nullable(),
47747
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
47748
+ switchOn: boolean().nullable(),
47749
+ switchOnline: boolean().nullable(),
47750
+ restartInProgress: boolean(),
47751
+ offSeconds: number().int()
47752
+ });
47753
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
47754
+ var PowerSourceStateSchema = object({
47755
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
47756
+ switchOn: boolean().nullable(),
47757
+ offSeconds: number().int(),
47758
+ lastFetchedAt: number()
47759
+ });
47760
+ var POWER_SOURCE_DEVICE_TYPES = [
47761
+ DeviceType.Gateway,
47762
+ DeviceType.Hub,
47763
+ DeviceType.Camera,
47764
+ DeviceType.Sensor,
47765
+ DeviceType.MediaPlayer,
47766
+ DeviceType.Vacuum,
47767
+ DeviceType.Generic,
47768
+ DeviceType.Washer,
47769
+ DeviceType.Dryer,
47770
+ DeviceType.Dishwasher,
47771
+ DeviceType.PetFountain,
47772
+ DeviceType.Fan,
47773
+ DeviceType.Humidifier,
47774
+ DeviceType.Climate,
47775
+ DeviceType.WaterHeater
47776
+ ];
47777
+ var powerSourceCustomize = {
47778
+ version: 1,
47779
+ targets: [{
47780
+ id: "switch",
47781
+ cardinality: "scalar",
47782
+ vocabulary: {
47783
+ cap: "power-source",
47784
+ stateField: "switchOn"
47785
+ },
47786
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
47787
+ apply: "add",
47788
+ path: "switchOn",
47789
+ sources: [{
47790
+ kind: "switch",
47791
+ transforms: [{ kind: "identity" }]
47792
+ }],
47793
+ companions: [{
47794
+ kind: "constant",
47795
+ path: "offSeconds",
47796
+ value: 10,
47797
+ when: "add"
47798
+ }, {
47799
+ kind: "clock",
47800
+ path: "lastFetchedAt",
47801
+ when: "always"
47802
+ }],
47803
+ sourceReport: { status: "assignment-status" }
47804
+ }]
47805
+ };
47806
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
47807
+ var powerSourceCapability = {
47808
+ name: "power-source",
47809
+ scope: "device",
47810
+ mode: "singleton",
47811
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
47812
+ methods: {
47813
+ getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
47814
+ powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47815
+ kind: "mutation",
47816
+ auth: "admin"
47817
+ }),
47818
+ powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47819
+ kind: "mutation",
47820
+ auth: "admin"
47821
+ }),
47822
+ forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47823
+ kind: "mutation",
47824
+ auth: "admin"
47825
+ })
47826
+ },
47827
+ runtimeState: PowerSourceStateSchema,
47828
+ customize: powerSourceCustomize,
47829
+ /**
47830
+ * Runtime-state durability: **session** — mirrored from the linked switch on
47831
+ * its next report; a restored value would outlive the reading it names.
47832
+ *
47833
+ * See `RuntimeStateDurability`. Enforced by
47834
+ * `scripts/check-runtime-state-durability.ts`.
47835
+ */
47836
+ durability: "session",
47837
+ history: "none"
47838
+ };
47720
47839
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
47721
47840
  DeviceType.Camera;
47722
47841
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
@@ -53755,7 +53874,8 @@ var PALETTE_ENTRY_IDS = [
53755
53874
  "switch",
53756
53875
  "siren",
53757
53876
  "button",
53758
- "doorbell"
53877
+ "doorbell",
53878
+ "appliance-cycle"
53759
53879
  ];
53760
53880
  var AUDIO_ENTRY_ID = "audio";
53761
53881
  /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
@@ -53826,7 +53946,8 @@ var CAMSTACK_HEX = {
53826
53946
  switch: "#7a812a",
53827
53947
  siren: "#ac5d7f",
53828
53948
  button: "#b276cd",
53829
- doorbell: "#0087ab"
53949
+ doorbell: "#0087ab",
53950
+ "appliance-cycle": "#2a8c8c"
53830
53951
  };
53831
53952
  var CAMSTACK_FALLBACK = [
53832
53953
  "#b34dc7",
@@ -53891,7 +54012,8 @@ var HIGH_CONTRAST_HEX = {
53891
54012
  switch: "#d05259",
53892
54013
  siren: "#cd67b3",
53893
54014
  button: "#c9746a",
53894
- doorbell: "#338eeb"
54015
+ doorbell: "#338eeb",
54016
+ "appliance-cycle": "#00848a"
53895
54017
  };
53896
54018
  var HIGH_CONTRAST_FALLBACK = [
53897
54019
  "#817f3b",
@@ -53956,7 +54078,8 @@ var OKABE_ITO_HEX = {
53956
54078
  switch: "#ad2c4e",
53957
54079
  siren: "#348e08",
53958
54080
  button: "#d27303",
53959
- doorbell: "#55770f"
54081
+ doorbell: "#55770f",
54082
+ "appliance-cycle": "#00737d"
53960
54083
  };
53961
54084
  var OKABE_ITO_FALLBACK = [
53962
54085
  "#9a3784",
@@ -54166,6 +54289,7 @@ sub("switch", "control", "control", "switch", "Switch");
54166
54289
  sub("siren", "control", "control", "siren", "Siren");
54167
54290
  sub("button", "control", "control", "button", "Button");
54168
54291
  sub("doorbell", "control", "control", "doorbell", "Doorbell");
54292
+ sub("appliance-cycle", "control", "control", "switch", "Appliance cycle");
54169
54293
  for (const l of AUDIO_MACRO_LABELS) {
54170
54294
  const kind = `audio-${l.id}`;
54171
54295
  if (entries.has(kind)) continue;
@@ -56528,17 +56652,17 @@ var NC_CONDITION_CATALOG = [
56528
56652
  options: [
56529
56653
  {
56530
56654
  value: "",
56531
- label: "It triggers and when it clears",
56532
- hint: "Every change: water detected, and back to dry."
56655
+ label: "When it starts and when it finishes",
56656
+ hint: "Every change: the alert itself, and the return to normal."
56533
56657
  },
56534
56658
  {
56535
56659
  value: "raised",
56536
- label: "Only when it triggers",
56660
+ label: "Only when it starts",
56537
56661
  hint: "Water detected, smoke, a contact opening — never the return to normal."
56538
56662
  },
56539
56663
  {
56540
56664
  value: "cleared",
56541
- label: "Only when it clears",
56665
+ label: "Only when it finishes",
56542
56666
  hint: "Back to dry, smoke gone, a contact closing — never the alert itself."
56543
56667
  }
56544
56668
  ],
@@ -64596,7 +64720,8 @@ var CAP_TO_KIND = {
64596
64720
  cover: "cover",
64597
64721
  switch: "switch",
64598
64722
  button: "button",
64599
- doorbell: "doorbell"
64723
+ doorbell: "doorbell",
64724
+ "running-state": "appliance-cycle"
64600
64725
  };
64601
64726
  function buildDescriptor(capName, kind) {
64602
64727
  const t = EVENT_TAXONOMY[kind];
@@ -69052,19 +69177,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
69052
69177
  reason: _enum(["unknown-template", "not-a-media-player"]),
69053
69178
  detail: string()
69054
69179
  })]);
69055
- var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
69180
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
69056
69181
  DeviceType.MediaPlayer;
69057
- method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
69182
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
69058
69183
  kind: "mutation",
69059
69184
  auth: "admin"
69060
- }), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
69185
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
69061
69186
  role: RemoteRoleSchema,
69062
69187
  /** Sends in a row (volume steps). */
69063
69188
  repeat: number().int().min(1).max(50).default(1)
69064
69189
  }), RemoteSendResultSchema, {
69065
69190
  kind: "mutation",
69066
69191
  auth: "protected"
69067
- }), method(deviceInput$1.extend({
69192
+ }), method(deviceInput.extend({
69068
69193
  command: RemoteMediaCommandSchema,
69069
69194
  muted: boolean().optional(),
69070
69195
  source: string().optional(),
@@ -73509,117 +73634,6 @@ var lockControlCapability = {
73509
73634
  * whether persisting is worth a SQLite commit. */
73510
73635
  volatileStateFields: ["lastChangedAt"]
73511
73636
  };
73512
- var PowerSourceRefusalReasonSchema = _enum([
73513
- "no-power-source",
73514
- "switch-missing",
73515
- "switch-offline",
73516
- "switch-unknown",
73517
- "restart-in-progress",
73518
- "switch-call-failed"
73519
- ]);
73520
- var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
73521
- accepted: literal(false),
73522
- reason: PowerSourceRefusalReasonSchema,
73523
- /** One line for the operator, naming the switch. */
73524
- message: string()
73525
- })]);
73526
- var PowerSourceInfoSchema = object({
73527
- /** False when the device has no power source linked; the rest is then empty. */
73528
- linked: boolean(),
73529
- switchDeviceId: number().nullable(),
73530
- switchName: string().nullable(),
73531
- /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
73532
- switchOn: boolean().nullable(),
73533
- switchOnline: boolean().nullable(),
73534
- restartInProgress: boolean(),
73535
- offSeconds: number().int()
73536
- });
73537
- /** The composed slice: the switch state the link mirrors, plus the stored off time. */
73538
- var PowerSourceStateSchema = object({
73539
- /** Null while the switch has not reported: unknown is never `false` (D393). */
73540
- switchOn: boolean().nullable(),
73541
- offSeconds: number().int(),
73542
- lastFetchedAt: number()
73543
- });
73544
- var POWER_SOURCE_DEVICE_TYPES = [
73545
- DeviceType.Gateway,
73546
- DeviceType.Hub,
73547
- DeviceType.Camera,
73548
- DeviceType.Sensor,
73549
- DeviceType.MediaPlayer,
73550
- DeviceType.Vacuum,
73551
- DeviceType.Generic,
73552
- DeviceType.Washer,
73553
- DeviceType.Dryer,
73554
- DeviceType.Dishwasher,
73555
- DeviceType.PetFountain,
73556
- DeviceType.Fan,
73557
- DeviceType.Humidifier,
73558
- DeviceType.Climate,
73559
- DeviceType.WaterHeater
73560
- ];
73561
- var powerSourceCustomize = {
73562
- version: 1,
73563
- targets: [{
73564
- id: "switch",
73565
- cardinality: "scalar",
73566
- vocabulary: {
73567
- cap: "power-source",
73568
- stateField: "switchOn"
73569
- },
73570
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73571
- apply: "add",
73572
- path: "switchOn",
73573
- sources: [{
73574
- kind: "switch",
73575
- transforms: [{ kind: "identity" }]
73576
- }],
73577
- companions: [{
73578
- kind: "constant",
73579
- path: "offSeconds",
73580
- value: 10,
73581
- when: "add"
73582
- }, {
73583
- kind: "clock",
73584
- path: "lastFetchedAt",
73585
- when: "always"
73586
- }],
73587
- sourceReport: { status: "assignment-status" }
73588
- }]
73589
- };
73590
- var deviceInput = object({ deviceId: number().int().nonnegative() });
73591
- var powerSourceCapability = {
73592
- name: "power-source",
73593
- scope: "device",
73594
- mode: "singleton",
73595
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73596
- methods: {
73597
- getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
73598
- powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73599
- kind: "mutation",
73600
- auth: "admin"
73601
- }),
73602
- powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73603
- kind: "mutation",
73604
- auth: "admin"
73605
- }),
73606
- forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73607
- kind: "mutation",
73608
- auth: "admin"
73609
- })
73610
- },
73611
- runtimeState: PowerSourceStateSchema,
73612
- customize: powerSourceCustomize,
73613
- /**
73614
- * Runtime-state durability: **session** — mirrored from the linked switch on
73615
- * its next report; a restored value would outlive the reading it names.
73616
- *
73617
- * See `RuntimeStateDurability`. Enforced by
73618
- * `scripts/check-runtime-state-durability.ts`.
73619
- */
73620
- durability: "session",
73621
- history: "none"
73622
- };
73623
73637
  /**
73624
73638
  * A monotonic total between resets (D944). Energy uses `power-meter.energy`
73625
73639
  * so dashboards keep one series; every other instantaneous reading lands here.
@@ -77221,6 +77235,10 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
77221
77235
  /** Generic Customize target for the running boolean (D936). */
77222
77236
  var runningCustomize = {
77223
77237
  version: 1,
77238
+ overridable: [{
77239
+ path: "running",
77240
+ by: "running"
77241
+ }],
77224
77242
  targets: [{
77225
77243
  id: "running",
77226
77244
  cardinality: "scalar",
@@ -77278,7 +77296,7 @@ var runningCustomize = {
77278
77296
  kind: "constant",
77279
77297
  path: "phase",
77280
77298
  value: null,
77281
- when: "always"
77299
+ when: "add"
77282
77300
  },
77283
77301
  {
77284
77302
  kind: "clock",
@@ -97392,7 +97410,8 @@ function isSystemDelivery(delivery) {
97392
97410
  * picker authors.
97393
97411
  *
97394
97412
  * Callers resolve the ids via `deviceManager.listDeviceIdsByCaps` (max 16
97395
- * names — `EVENTFUL_CAP_NAMES` is exactly 16) and must treat an unanswered
97413
+ * names per call — `EVENTFUL_CAP_NAMES` is longer than that, so ask through
97414
+ * {@link ruleDeviceCompatCapQueries}, which chunks it) and must treat an unanswered
97396
97415
  * read as "unknown", never as "no devices" (D315): this function only names
97397
97416
  * WHICH caps to ask for, not what to show while the answer is pending.
97398
97417
  */
@@ -97414,6 +97433,12 @@ function ruleDeviceCompatCapNames(kind) {
97414
97433
  * Named once, because a sensor rule's compatible set needs it (below).
97415
97434
  */
97416
97435
  var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97436
+ var MAX_CAPS_PER_QUERY = 16;
97437
+ function chunk(items, size) {
97438
+ const out = [];
97439
+ for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
97440
+ return out;
97441
+ }
97417
97442
  /**
97418
97443
  * Every capability QUERY whose union is the set of devices a rule of this kind
97419
97444
  * may be SCOPED to (`conditions.devices`) — what the save-time guard and the
@@ -97421,7 +97446,7 @@ var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97421
97446
  * entry. `null` exactly where {@link ruleDeviceCompatCapNames} is `null`.
97422
97447
  *
97423
97448
  * Several queries rather than one list because `listDeviceIdsByCaps` takes at
97424
- * most 16 names and `EVENTFUL_CAP_NAMES` is already exactly 16.
97449
+ * most 16 names and `EVENTFUL_CAP_NAMES` is longer than that (chunked here).
97425
97450
  *
97426
97451
  * A `sensor` rule's set is the eventful devices PLUS every camera (fix round
97427
97452
  * 1, 2026-10-01): the engine matches a sensor rule scoped to a CAMERA — a
@@ -97432,7 +97457,8 @@ var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97432
97457
  function ruleDeviceCompatCapQueries(kind) {
97433
97458
  const primary = ruleDeviceCompatCapNames(kind);
97434
97459
  if (primary === null) return null;
97435
- return kind === "sensor" ? [primary, [NC_CAMERA_SCOPE_CAP_NAME]] : [primary];
97460
+ const chunks = chunk(primary, MAX_CAPS_PER_QUERY);
97461
+ return kind === "sensor" ? [...chunks, [NC_CAMERA_SCOPE_CAP_NAME]] : chunks;
97436
97462
  }
97437
97463
  /**
97438
97464
  * Which kind of rule is this?
@@ -98336,8 +98362,17 @@ function syncActiveAlarmProfileSettings(state, settings) {
98336
98362
  *
98337
98363
  * Pure, RN-safe: the viewer imports the support rule from here.
98338
98364
  */
98365
+ /**
98366
+ * Control caps that still have a raise and a clear an operator names: an
98367
+ * appliance cycle raises when it STARTS and clears when it FINISHES. Kept out
98368
+ * of `SOURCE_CAP_ACTIVE_FIELD` on purpose — that table also makes a device a
98369
+ * camera-sensor / recorder-trigger source, and a dishwasher is neither.
98370
+ */
98371
+ var CYCLE_RAISED_FIELD_BY_CAP = { "running-state": "running" };
98339
98372
  /** Event kind → the boolean field of its cap slice that means "raised". */
98340
98373
  var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
98374
+ const cycleField = CYCLE_RAISED_FIELD_BY_CAP[capName];
98375
+ if (cycleField !== void 0) return [[descriptor.kind, cycleField]];
98341
98376
  const field = SOURCE_CAP_ACTIVE_FIELD[capName];
98342
98377
  if (field === void 0 || descriptor.category !== "sensor") return [];
98343
98378
  return [[descriptor.kind, field]];
@@ -98358,6 +98393,98 @@ function sensorRaisedOf(kind, value) {
98358
98393
  const raw = Object.entries(value).find(([key]) => key === field)?.[1];
98359
98394
  return typeof raw === "boolean" ? raw : void 0;
98360
98395
  }
98396
+ Object.freeze({
98397
+ contact: {
98398
+ starts: {
98399
+ en: "opened",
98400
+ it: "si apre"
98401
+ },
98402
+ finishes: {
98403
+ en: "closed",
98404
+ it: "si chiude"
98405
+ }
98406
+ },
98407
+ "motion-sensor": {
98408
+ starts: {
98409
+ en: "motion detected",
98410
+ it: "movimento rilevato"
98411
+ },
98412
+ finishes: {
98413
+ en: "motion stopped",
98414
+ it: "movimento terminato"
98415
+ }
98416
+ },
98417
+ smoke: {
98418
+ starts: {
98419
+ en: "smoke detected",
98420
+ it: "fumo rilevato"
98421
+ },
98422
+ finishes: {
98423
+ en: "smoke gone",
98424
+ it: "fumo scomparso"
98425
+ }
98426
+ },
98427
+ flood: {
98428
+ starts: {
98429
+ en: "water detected",
98430
+ it: "acqua rilevata"
98431
+ },
98432
+ finishes: {
98433
+ en: "dry again",
98434
+ it: "di nuovo asciutto"
98435
+ }
98436
+ },
98437
+ gas: {
98438
+ starts: {
98439
+ en: "gas detected",
98440
+ it: "gas rilevato"
98441
+ },
98442
+ finishes: {
98443
+ en: "gas gone",
98444
+ it: "gas scomparso"
98445
+ }
98446
+ },
98447
+ "carbon-monoxide": {
98448
+ starts: {
98449
+ en: "carbon monoxide detected",
98450
+ it: "monossido rilevato"
98451
+ },
98452
+ finishes: {
98453
+ en: "carbon monoxide gone",
98454
+ it: "monossido scomparso"
98455
+ }
98456
+ },
98457
+ vibration: {
98458
+ starts: {
98459
+ en: "vibration detected",
98460
+ it: "vibrazione rilevata"
98461
+ },
98462
+ finishes: {
98463
+ en: "vibration stopped",
98464
+ it: "vibrazione terminata"
98465
+ }
98466
+ },
98467
+ tamper: {
98468
+ starts: {
98469
+ en: "tampered with",
98470
+ it: "manomesso"
98471
+ },
98472
+ finishes: {
98473
+ en: "tamper cleared",
98474
+ it: "manomissione rientrata"
98475
+ }
98476
+ },
98477
+ "appliance-cycle": {
98478
+ starts: {
98479
+ en: "the cycle started",
98480
+ it: "il ciclo parte"
98481
+ },
98482
+ finishes: {
98483
+ en: "the cycle finished",
98484
+ it: "il ciclo è terminato"
98485
+ }
98486
+ }
98487
+ });
98361
98488
  /**
98362
98489
  * An alert EPISODE as a notification subject.
98363
98490
  *
@@ -100077,6 +100204,7 @@ var EVENT_KIND_LABEL_KEYS = [
100077
100204
  "siren",
100078
100205
  "button",
100079
100206
  "doorbell",
100207
+ "appliance-cycle",
100080
100208
  "audio-speech",
100081
100209
  "audio-scream",
100082
100210
  "audio-crying",
@@ -100284,6 +100412,10 @@ var EVENT_KIND_LABELS = {
100284
100412
  en: "Doorbell",
100285
100413
  it: "Campanello"
100286
100414
  },
100415
+ "appliance-cycle": {
100416
+ en: "Appliance cycle",
100417
+ it: "Ciclo elettrodomestico"
100418
+ },
100287
100419
  "audio-speech": {
100288
100420
  en: "Speech",
100289
100421
  it: "Voce"