@camstack/addon-provider-homematic 1.2.120 → 1.2.121

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
@@ -5379,7 +5379,7 @@ var ZodIssueCode = {
5379
5379
  var ZodFirstPartyTypeKind;
5380
5380
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5381
5381
  //#endregion
5382
- //#region ../types/dist/sleep-DlrgY4Qb.mjs
5382
+ //#region ../types/dist/sleep-C-v96WpE.mjs
5383
5383
  /**
5384
5384
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5385
5385
  * window to float samples (D455).
@@ -8228,7 +8228,6 @@ var CompositionSchema = object({
8228
8228
  });
8229
8229
  new Set([
8230
8230
  "track",
8231
- "summary",
8232
8231
  "face",
8233
8232
  "identity",
8234
8233
  "plate",
@@ -20537,6 +20536,102 @@ var OauthIntegrationDescriptorSchema = object({
20537
20536
  });
20538
20537
  method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
20539
20538
  /**
20539
+ * What started a camera's onboard motion (D672). `camera` is the camera's own
20540
+ * firmware; `sensor` is a device the operator ATTACHED to it. Absent on the
20541
+ * wire means the camera: only the camera-sensors bridge ever says `sensor`.
20542
+ */
20543
+ var MotionTriggeredBySchema = discriminatedUnion("kind", [object({ kind: literal("camera") }), object({
20544
+ kind: literal("sensor"),
20545
+ deviceId: number().int().positive()
20546
+ })]);
20547
+ Object.freeze({ kind: "camera" });
20548
+ var CameraSensorRefSchema = object({
20549
+ addonId: string().min(1),
20550
+ stableId: string().min(1)
20551
+ });
20552
+ function cameraSensorRefKey(ref) {
20553
+ return `${ref.addonId}/${ref.stableId}`;
20554
+ }
20555
+ /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20556
+ var CameraSensorsModeSchema = _enum(["in-addition"]);
20557
+ object({
20558
+ mode: CameraSensorsModeSchema,
20559
+ sensors: array(CameraSensorRefSchema).min(1).max(8)
20560
+ }).superRefine((value, ctx) => {
20561
+ const seen = /* @__PURE__ */ new Set();
20562
+ value.sensors.forEach((ref, index) => {
20563
+ const key = cameraSensorRefKey(ref);
20564
+ if (seen.has(key)) ctx.addIssue({
20565
+ code: "custom",
20566
+ path: ["sensors", index],
20567
+ message: `duplicate camera sensor ${key}`
20568
+ });
20569
+ seen.add(key);
20570
+ });
20571
+ });
20572
+ var RefFields = {
20573
+ addonId: string(),
20574
+ stableId: string()
20575
+ };
20576
+ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20577
+ object({
20578
+ ...RefFields,
20579
+ state: literal("ready"),
20580
+ deviceId: number(),
20581
+ name: string(),
20582
+ caps: array(string()).readonly()
20583
+ }),
20584
+ object({
20585
+ ...RefFields,
20586
+ state: literal("offline"),
20587
+ deviceId: number(),
20588
+ name: string(),
20589
+ reason: _enum(["offline", "disabled"])
20590
+ }),
20591
+ object({
20592
+ ...RefFields,
20593
+ state: literal("missing"),
20594
+ reason: string()
20595
+ }),
20596
+ object({
20597
+ ...RefFields,
20598
+ state: literal("unsupported"),
20599
+ deviceId: number(),
20600
+ name: string(),
20601
+ reason: string()
20602
+ }),
20603
+ object({
20604
+ ...RefFields,
20605
+ state: literal("unreadable"),
20606
+ reason: string()
20607
+ })
20608
+ ]);
20609
+ /**
20610
+ * Why a configured camera forwards NOTHING from its sensors, however ready they
20611
+ * are (D672): it does not list `onboard` in `motionSources` (attaching a sensor
20612
+ * does not add it), or it has no active detection config at all (the bridge
20613
+ * reads the active config). Absent = forwarded, or an older node that does not
20614
+ * say.
20615
+ */
20616
+ var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20617
+ var CameraSensorsStatusSchema = discriminatedUnion("state", [
20618
+ object({ state: literal("not-configured") }),
20619
+ object({
20620
+ state: literal("unreadable"),
20621
+ reason: string()
20622
+ }),
20623
+ object({
20624
+ state: literal("configured"),
20625
+ mode: CameraSensorsModeSchema,
20626
+ sensors: array(CameraSensorAttachmentSchema).readonly(),
20627
+ notForwarded: CameraSensorsNotForwardedSchema.optional()
20628
+ })
20629
+ ]);
20630
+ Object.freeze({
20631
+ state: "unreadable",
20632
+ reason: "camera sensor mappings not loaded"
20633
+ });
20634
+ /**
20540
20635
  * A model choice has a SCOPE, and a scope change has a workflow.
20541
20636
  *
20542
20637
  * ## The two scopes
@@ -21285,6 +21380,12 @@ var MotionEventSchema = object({
21285
21380
  /** Populated by B5 (recording playback URL for this event). */
21286
21381
  mediaUrl: string().optional(),
21287
21382
  /**
21383
+ * The FIRST trigger of an `onboard` episode, written once at open (D672).
21384
+ * Absent = not recorded (a row written before D672, or an analyzer /
21385
+ * device-activity episode) — never read as "the camera" (D393).
21386
+ */
21387
+ triggeredBy: MotionTriggeredBySchema.optional(),
21388
+ /**
21288
21389
  * One row per motion EPISODE, not one per push (D475). `null` while the
21289
21390
  * episode is still open — a further rising edge extends it in place rather
21290
21391
  * than inserting a new row. Set once, at close, to `lastOnAt - startedAt`
@@ -21443,6 +21544,21 @@ var ObjectEventSchema = object({
21443
21544
  keyFrameMediaId: number().int().optional(),
21444
21545
  /** Populated by B5 (recording playback URL for this event). */
21445
21546
  mediaUrl: string().optional(),
21547
+ /**
21548
+ * When the change this row records HAPPENED, epoch ms, when that is earlier
21549
+ * than {@link timestamp} and the producer could date it (D684).
21550
+ *
21551
+ * Set on a package PICK-UP row only: its `timestamp` is when the departure
21552
+ * was CONCLUDED — five minutes of unseen observed time after the parcel went
21553
+ * — and a notification's footage has to be cut around the pick-up, not the
21554
+ * empty doormat after it (D682). Stored so every path that rebuilds a
21555
+ * notification subject from the row (the boot reconcile, a dry-run) anchors
21556
+ * on the same instant the live hook did.
21557
+ *
21558
+ * `timestamp` keeps its meaning. Absent on every other row and on every
21559
+ * pick-up written before D684 — UNKNOWN, never 0 and never `timestamp`.
21560
+ */
21561
+ observedAt: number().optional(),
21446
21562
  /** The parent track's key-event importance [0,1], propagated to every object
21447
21563
  * event of the track (so an event row can be sorted by importance without a
21448
21564
  * track join). Absent on legacy rows / before the track was scored. */
@@ -21778,131 +21894,6 @@ var RecentTracksQueryInput = object({
21778
21894
  /** See {@link ExcludeSourcesDoc}. */
21779
21895
  excludeSources: array(TrackSourceSchema).optional()
21780
21896
  });
21781
- /**
21782
- * A Summary (D359): the per-camera session envelope that references tracks.
21783
- * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
21784
- * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
21785
- * first frame with a member visible has been materialised (D482 — it was the
21786
- * row's composite key, which embedded the owner and could name another table's
21787
- * row once event ids became per-table rowids).
21788
- */
21789
- var SummarySchema = object({
21790
- id: string(),
21791
- deviceId: number(),
21792
- openedAt: number(),
21793
- lastActiveAt: number(),
21794
- sealedAt: number().nullable(),
21795
- memberCount: number().int().nonnegative(),
21796
- groupShotMediaId: number().int().nullable()
21797
- });
21798
- var SummariesQueryInput = object({
21799
- deviceIds: array(number()).min(1),
21800
- since: number().optional(),
21801
- until: number().optional(),
21802
- limit: number().int().min(1).max(200).default(50),
21803
- /** The same member-wise filter {@link listRecentSummaries} takes — one
21804
- * meaning of "dog" on every summary surface. */
21805
- classes: array(string().min(1).max(60)).max(40).optional()
21806
- });
21807
- var SummaryDetailSchema = object({
21808
- summary: SummarySchema,
21809
- /** Members in absorption order, oldest join first. */
21810
- members: array(object({
21811
- trackId: string(),
21812
- /**
21813
- * The track's class at the time it JOINED, or `null` when it was unresolved
21814
- * and the track no longer exists to fill it.
21815
- *
21816
- * The join, not the latest opinion: class voting can re-decide a track's
21817
- * class afterwards, and a group's composition is the history of who came
21818
- * together. A consumer counts these to badge a thumbnail — "two people and a
21819
- * dog" — rather than being handed a second, denormalised tally that would
21820
- * drift from the members it claims to describe.
21821
- */
21822
- className: string().nullable(),
21823
- /** `primary` is the one member that carries the group's identity. */
21824
- role: _enum([
21825
- "primary",
21826
- "sibling",
21827
- "child"
21828
- ]).nullable(),
21829
- joinedAt: number(),
21830
- /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
21831
- * at read time. Absent when nothing resolved, never an empty string. */
21832
- label: string().optional(),
21833
- /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
21834
- * recognised nobody, and absent for a member whose track has been pruned —
21835
- * a thumbnail that names the wrong person is worse than one naming nobody. */
21836
- subLabel: string().optional()
21837
- })).readonly()
21838
- });
21839
- /**
21840
- * What a LIST of groups carries: the envelope plus what it is MADE OF.
21841
- *
21842
- * Coarse on purpose — the operator's rule is "only the rough data on the list,
21843
- * we extend when we notice we need more". Enough to draw the card ("two people
21844
- * and a dog") and no more. The MEMBERS, their names and the per-member links
21845
- * are on {@link getSummary}: shipping every member of every group so a client
21846
- * can count them turns a page of two hundred groups into a thousand records to
21847
- * draw two hundred badges.
21848
- */
21849
- var SummaryListItemSchema = object({
21850
- summary: SummarySchema,
21851
- /** Class counts, most numerous first; `className: null` is a member whose
21852
- * class never resolved, counted so the counts add up to `memberCount`. */
21853
- classes: array(object({
21854
- className: string().nullable(),
21855
- count: number().int().positive()
21856
- })).readonly()
21857
- });
21858
- var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
21859
- /**
21860
- * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
21861
- *
21862
- * The reel on the cameras page and the Events gallery both ride a cursor, so a
21863
- * summaries feed that could only answer "the last N for these cameras"
21864
- * (`listSummaries`) would make groups available in the timeline and nowhere
21865
- * else. Two feeds with different ordering contracts would be two ideas of what
21866
- * "newest" means, on one screen.
21867
- */
21868
- var RecentSummariesQueryInput = object({
21869
- /** Devices to merge. An empty array yields an empty page. */
21870
- deviceIds: array(number()),
21871
- /** Window lower bound on `lastActiveAt` (inclusive). */
21872
- since: number().optional(),
21873
- /** Window upper bound on `lastActiveAt` (inclusive). */
21874
- until: number().optional(),
21875
- limit: number().int().min(1).max(500).default(100),
21876
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
21877
- cursor: string().optional(),
21878
- /**
21879
- * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
21880
- * deliberately the same name: the events filter tree emits one list of ticked
21881
- * taxonomy nodes, and a summaries feed that called it something else would
21882
- * make the operator's one filter component produce two shapes.
21883
- *
21884
- * A question about the MEMBERS: a group matches when ANY of them does. "Show
21885
- * me the arrivals with a dog" has to return the group of four people who had
21886
- * one with them; a filter on the group's own fields could only ever answer
21887
- * about its primary.
21888
- *
21889
- * Matched against all THREE tiers of a member — the class (`animal`), the
21890
- * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
21891
- * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
21892
- * an event kind in the tree and a tier-1 label on an `animal` track; a filter
21893
- * that read only the class would answer "animal" and never "dog".
21894
- *
21895
- * ABSENT or EMPTY means no filter — absent is not a selection of none.
21896
- */
21897
- classes: array(string().min(1).max(60)).max(40).optional()
21898
- });
21899
- var RecentSummariesPageSchema = object({
21900
- /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
21901
- * {@link listSummaries} — one list shape, so a card renders the same
21902
- * whichever feed drew it. */
21903
- summaries: array(SummaryListItemSchema).readonly(),
21904
- nextCursor: string().nullable()
21905
- });
21906
21897
  var RecentTracksPageSchema = object({
21907
21898
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
21908
21899
  tracks: array(TrackSchema).readonly(),
@@ -22414,7 +22405,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
22414
22405
  classes: array(string()).optional(),
22415
22406
  /** See {@link ExcludeSourcesDoc}. */
22416
22407
  excludeSources: array(TrackSourceSchema).optional()
22417
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
22408
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
22418
22409
  kind: "mutation",
22419
22410
  auth: "admin"
22420
22411
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -23634,6 +23625,23 @@ var MotionSourceEnum = _enum([
23634
23625
  */
23635
23626
  var MotionSourcesSchema = array(MotionSourceEnum);
23636
23627
  /**
23628
+ * The operator-facing name of each MOTION source (D672: `onboard` = the
23629
+ * camera's sensors — its own motion plus any sensor attached to it). The wire
23630
+ * value stays `onboard`; only the label changed. `detectionSources: 'onboard'`
23631
+ * ("Camera onboard AI") and the notification source filter keep their labels.
23632
+ */
23633
+ var MOTION_SOURCE_LABELS = {
23634
+ analyzer: "Frame-diff Analyzer (motion addon)",
23635
+ onboard: "Camera sensors",
23636
+ "device-activity": "Device activity (the device says it is working)"
23637
+ };
23638
+ /** The order the motion-source picker offers them in (not the enum's order). */
23639
+ var MOTION_SOURCE_PICKER_ORDER = [
23640
+ "analyzer",
23641
+ "onboard",
23642
+ "device-activity"
23643
+ ];
23644
+ /**
23637
23645
  * Which root detector a camera runs — EXACTLY ONE.
23638
23646
  *
23639
23647
  * Deliberately the SAME vocabulary post-analysis already tags every detection
@@ -23980,7 +23988,14 @@ var RunnerCameraConfigSchema = object({
23980
23988
  */
23981
23989
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
23982
23990
  });
23983
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
23991
+ MOTION_SOURCE_PICKER_ORDER.map((value) => value === "onboard" ? {
23992
+ value,
23993
+ label: MOTION_SOURCE_LABELS[value],
23994
+ description: "The camera's own motion, plus any sensor attached to it"
23995
+ } : {
23996
+ value,
23997
+ label: MOTION_SOURCE_LABELS[value]
23998
+ }), motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
23984
23999
  /**
23985
24000
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
23986
24001
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -24554,6 +24569,11 @@ var CameraStatusSchema = object({
24554
24569
  */
24555
24570
  switchedOff: array(CameraSwitchIdSchema).readonly(),
24556
24571
  /**
24572
+ * The camera's attached sensors (D672). Optional only for a status composed
24573
+ * by an orchestrator older than D672; this orchestrator always sets it.
24574
+ */
24575
+ cameraSensors: CameraSensorsStatusSchema.optional(),
24576
+ /**
24557
24577
  * Stages of the bounded fan-out that were CUT SHORT — a timeout or a
24558
24578
  * rejection — and whose block is therefore `null` because we could not
24559
24579
  * READ it, not because there is nothing there.
@@ -31892,7 +31912,9 @@ var MotionOnMotionChangedDataSchema = object({
31892
31912
  detected: boolean(),
31893
31913
  timestamp: number(),
31894
31914
  source: MotionSourceEnum,
31895
- regions: array(MotionRegionSchema).readonly().optional()
31915
+ regions: array(MotionRegionSchema).readonly().optional(),
31916
+ /** Who started it (D672). Absent = the camera itself. Only `onboard` carries `sensor`. */
31917
+ triggeredBy: MotionTriggeredBySchema.optional()
31896
31918
  });
31897
31919
  var motionCapability = {
31898
31920
  name: "motion",
@@ -45338,12 +45360,6 @@ Object.freeze({
45338
45360
  addonId: null,
45339
45361
  access: "view"
45340
45362
  },
45341
- "pipelineAnalytics.getSummary": {
45342
- capName: "pipeline-analytics",
45343
- capScope: "device",
45344
- addonId: null,
45345
- access: "view"
45346
- },
45347
45363
  "pipelineAnalytics.getTrack": {
45348
45364
  capName: "pipeline-analytics",
45349
45365
  capScope: "device",
@@ -45404,12 +45420,6 @@ Object.freeze({
45404
45420
  addonId: null,
45405
45421
  access: "view"
45406
45422
  },
45407
- "pipelineAnalytics.listRecentSummaries": {
45408
- capName: "pipeline-analytics",
45409
- capScope: "device",
45410
- addonId: null,
45411
- access: "view"
45412
- },
45413
45423
  "pipelineAnalytics.listRecentTracks": {
45414
45424
  capName: "pipeline-analytics",
45415
45425
  capScope: "device",
@@ -45440,12 +45450,6 @@ Object.freeze({
45440
45450
  addonId: null,
45441
45451
  access: "view"
45442
45452
  },
45443
- "pipelineAnalytics.listSummaries": {
45444
- capName: "pipeline-analytics",
45445
- capScope: "device",
45446
- addonId: null,
45447
- access: "view"
45448
- },
45449
45453
  "pipelineAnalytics.listTrackMedia": {
45450
45454
  capName: "pipeline-analytics",
45451
45455
  capScope: "device",
@@ -49615,11 +49619,6 @@ Object.freeze({
49615
49619
  form: "single",
49616
49620
  optional: true
49617
49621
  }],
49618
- "pipelineAnalytics.listRecentSummaries": [{
49619
- name: "deviceIds",
49620
- form: "array",
49621
- optional: false
49622
- }],
49623
49622
  "pipelineAnalytics.listRecentTracks": [{
49624
49623
  name: "deviceIds",
49625
49624
  form: "array",
@@ -49630,11 +49629,6 @@ Object.freeze({
49630
49629
  form: "array",
49631
49630
  optional: true
49632
49631
  }],
49633
- "pipelineAnalytics.listSummaries": [{
49634
- name: "deviceIds",
49635
- form: "array",
49636
- optional: false
49637
- }],
49638
49632
  "pipelineAnalytics.listTrackMedia": [{
49639
49633
  name: "deviceId",
49640
49634
  form: "single",
@@ -75142,6 +75136,20 @@ var COLD_MOTION = {
75142
75136
  lastDetectedAt: null,
75143
75137
  autoClearAfterMs: null
75144
75138
  };
75139
+ /**
75140
+ * The motion seed a constructor writes OVER the slice hydrated from the
75141
+ * persisted runtime state. The level is a placeholder (`false`) until the
75142
+ * CCU says otherwise, but a stored rise is a fact: `lastDetectedAt: null`
75143
+ * means "never detected" (`motion.cap.ts`), and a restart must not turn
75144
+ * "fired an hour ago" into that.
75145
+ */
75146
+ function coldMotionKeepingRise(stored) {
75147
+ const rise = stored?.lastDetectedAt;
75148
+ return {
75149
+ ...COLD_MOTION,
75150
+ lastDetectedAt: typeof rise === "number" && Number.isFinite(rise) && rise > 0 ? rise : null
75151
+ };
75152
+ }
75145
75153
  var COLD_CLIMATE = {
75146
75154
  mode: "auto",
75147
75155
  availableModes: [...[
@@ -76691,7 +76699,7 @@ var HmSensorDevice = class extends HmChildDevice {
76691
76699
  getStatus: async () => this.runtimeState.getCapState("motion") ?? COLD_MOTION,
76692
76700
  isDetected: async () => (this.runtimeState.getCapState("motion") ?? COLD_MOTION).detected
76693
76701
  });
76694
- this.runtimeState.setCapState("motion", COLD_MOTION);
76702
+ this.runtimeState.setCapState("motion", coldMotionKeepingRise(this.runtimeState.getCapState("motion")));
76695
76703
  }
76696
76704
  handleValueChanged(event, origin) {
76697
76705
  const now = event.ts || Date.now();
@@ -77735,6 +77743,7 @@ exports.HomematicProviderAddon = HomematicProviderAddon;
77735
77743
  exports.buildConnectionFormSchema = buildConnectionFormSchema;
77736
77744
  exports.buildDeviceAdminUrl = buildDeviceAdminUrl;
77737
77745
  exports.climateControlCapability = climateControlCapability;
77746
+ exports.coldMotionKeepingRise = coldMotionKeepingRise;
77738
77747
  exports.coverCapability = coverCapability;
77739
77748
  exports.createEvent = createEvent;
77740
77749
  exports.decodeClimate = decodeClimate;
package/dist/addon.mjs CHANGED
@@ -5380,7 +5380,7 @@ var ZodIssueCode = {
5380
5380
  var ZodFirstPartyTypeKind;
5381
5381
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5382
5382
  //#endregion
5383
- //#region ../types/dist/sleep-DlrgY4Qb.mjs
5383
+ //#region ../types/dist/sleep-C-v96WpE.mjs
5384
5384
  /**
5385
5385
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5386
5386
  * window to float samples (D455).
@@ -8229,7 +8229,6 @@ var CompositionSchema = object({
8229
8229
  });
8230
8230
  new Set([
8231
8231
  "track",
8232
- "summary",
8233
8232
  "face",
8234
8233
  "identity",
8235
8234
  "plate",
@@ -20538,6 +20537,102 @@ var OauthIntegrationDescriptorSchema = object({
20538
20537
  });
20539
20538
  method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
20540
20539
  /**
20540
+ * What started a camera's onboard motion (D672). `camera` is the camera's own
20541
+ * firmware; `sensor` is a device the operator ATTACHED to it. Absent on the
20542
+ * wire means the camera: only the camera-sensors bridge ever says `sensor`.
20543
+ */
20544
+ var MotionTriggeredBySchema = discriminatedUnion("kind", [object({ kind: literal("camera") }), object({
20545
+ kind: literal("sensor"),
20546
+ deviceId: number().int().positive()
20547
+ })]);
20548
+ Object.freeze({ kind: "camera" });
20549
+ var CameraSensorRefSchema = object({
20550
+ addonId: string().min(1),
20551
+ stableId: string().min(1)
20552
+ });
20553
+ function cameraSensorRefKey(ref) {
20554
+ return `${ref.addonId}/${ref.stableId}`;
20555
+ }
20556
+ /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20557
+ var CameraSensorsModeSchema = _enum(["in-addition"]);
20558
+ object({
20559
+ mode: CameraSensorsModeSchema,
20560
+ sensors: array(CameraSensorRefSchema).min(1).max(8)
20561
+ }).superRefine((value, ctx) => {
20562
+ const seen = /* @__PURE__ */ new Set();
20563
+ value.sensors.forEach((ref, index) => {
20564
+ const key = cameraSensorRefKey(ref);
20565
+ if (seen.has(key)) ctx.addIssue({
20566
+ code: "custom",
20567
+ path: ["sensors", index],
20568
+ message: `duplicate camera sensor ${key}`
20569
+ });
20570
+ seen.add(key);
20571
+ });
20572
+ });
20573
+ var RefFields = {
20574
+ addonId: string(),
20575
+ stableId: string()
20576
+ };
20577
+ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20578
+ object({
20579
+ ...RefFields,
20580
+ state: literal("ready"),
20581
+ deviceId: number(),
20582
+ name: string(),
20583
+ caps: array(string()).readonly()
20584
+ }),
20585
+ object({
20586
+ ...RefFields,
20587
+ state: literal("offline"),
20588
+ deviceId: number(),
20589
+ name: string(),
20590
+ reason: _enum(["offline", "disabled"])
20591
+ }),
20592
+ object({
20593
+ ...RefFields,
20594
+ state: literal("missing"),
20595
+ reason: string()
20596
+ }),
20597
+ object({
20598
+ ...RefFields,
20599
+ state: literal("unsupported"),
20600
+ deviceId: number(),
20601
+ name: string(),
20602
+ reason: string()
20603
+ }),
20604
+ object({
20605
+ ...RefFields,
20606
+ state: literal("unreadable"),
20607
+ reason: string()
20608
+ })
20609
+ ]);
20610
+ /**
20611
+ * Why a configured camera forwards NOTHING from its sensors, however ready they
20612
+ * are (D672): it does not list `onboard` in `motionSources` (attaching a sensor
20613
+ * does not add it), or it has no active detection config at all (the bridge
20614
+ * reads the active config). Absent = forwarded, or an older node that does not
20615
+ * say.
20616
+ */
20617
+ var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20618
+ var CameraSensorsStatusSchema = discriminatedUnion("state", [
20619
+ object({ state: literal("not-configured") }),
20620
+ object({
20621
+ state: literal("unreadable"),
20622
+ reason: string()
20623
+ }),
20624
+ object({
20625
+ state: literal("configured"),
20626
+ mode: CameraSensorsModeSchema,
20627
+ sensors: array(CameraSensorAttachmentSchema).readonly(),
20628
+ notForwarded: CameraSensorsNotForwardedSchema.optional()
20629
+ })
20630
+ ]);
20631
+ Object.freeze({
20632
+ state: "unreadable",
20633
+ reason: "camera sensor mappings not loaded"
20634
+ });
20635
+ /**
20541
20636
  * A model choice has a SCOPE, and a scope change has a workflow.
20542
20637
  *
20543
20638
  * ## The two scopes
@@ -21286,6 +21381,12 @@ var MotionEventSchema = object({
21286
21381
  /** Populated by B5 (recording playback URL for this event). */
21287
21382
  mediaUrl: string().optional(),
21288
21383
  /**
21384
+ * The FIRST trigger of an `onboard` episode, written once at open (D672).
21385
+ * Absent = not recorded (a row written before D672, or an analyzer /
21386
+ * device-activity episode) — never read as "the camera" (D393).
21387
+ */
21388
+ triggeredBy: MotionTriggeredBySchema.optional(),
21389
+ /**
21289
21390
  * One row per motion EPISODE, not one per push (D475). `null` while the
21290
21391
  * episode is still open — a further rising edge extends it in place rather
21291
21392
  * than inserting a new row. Set once, at close, to `lastOnAt - startedAt`
@@ -21444,6 +21545,21 @@ var ObjectEventSchema = object({
21444
21545
  keyFrameMediaId: number().int().optional(),
21445
21546
  /** Populated by B5 (recording playback URL for this event). */
21446
21547
  mediaUrl: string().optional(),
21548
+ /**
21549
+ * When the change this row records HAPPENED, epoch ms, when that is earlier
21550
+ * than {@link timestamp} and the producer could date it (D684).
21551
+ *
21552
+ * Set on a package PICK-UP row only: its `timestamp` is when the departure
21553
+ * was CONCLUDED — five minutes of unseen observed time after the parcel went
21554
+ * — and a notification's footage has to be cut around the pick-up, not the
21555
+ * empty doormat after it (D682). Stored so every path that rebuilds a
21556
+ * notification subject from the row (the boot reconcile, a dry-run) anchors
21557
+ * on the same instant the live hook did.
21558
+ *
21559
+ * `timestamp` keeps its meaning. Absent on every other row and on every
21560
+ * pick-up written before D684 — UNKNOWN, never 0 and never `timestamp`.
21561
+ */
21562
+ observedAt: number().optional(),
21447
21563
  /** The parent track's key-event importance [0,1], propagated to every object
21448
21564
  * event of the track (so an event row can be sorted by importance without a
21449
21565
  * track join). Absent on legacy rows / before the track was scored. */
@@ -21779,131 +21895,6 @@ var RecentTracksQueryInput = object({
21779
21895
  /** See {@link ExcludeSourcesDoc}. */
21780
21896
  excludeSources: array(TrackSourceSchema).optional()
21781
21897
  });
21782
- /**
21783
- * A Summary (D359): the per-camera session envelope that references tracks.
21784
- * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
21785
- * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
21786
- * first frame with a member visible has been materialised (D482 — it was the
21787
- * row's composite key, which embedded the owner and could name another table's
21788
- * row once event ids became per-table rowids).
21789
- */
21790
- var SummarySchema = object({
21791
- id: string(),
21792
- deviceId: number(),
21793
- openedAt: number(),
21794
- lastActiveAt: number(),
21795
- sealedAt: number().nullable(),
21796
- memberCount: number().int().nonnegative(),
21797
- groupShotMediaId: number().int().nullable()
21798
- });
21799
- var SummariesQueryInput = object({
21800
- deviceIds: array(number()).min(1),
21801
- since: number().optional(),
21802
- until: number().optional(),
21803
- limit: number().int().min(1).max(200).default(50),
21804
- /** The same member-wise filter {@link listRecentSummaries} takes — one
21805
- * meaning of "dog" on every summary surface. */
21806
- classes: array(string().min(1).max(60)).max(40).optional()
21807
- });
21808
- var SummaryDetailSchema = object({
21809
- summary: SummarySchema,
21810
- /** Members in absorption order, oldest join first. */
21811
- members: array(object({
21812
- trackId: string(),
21813
- /**
21814
- * The track's class at the time it JOINED, or `null` when it was unresolved
21815
- * and the track no longer exists to fill it.
21816
- *
21817
- * The join, not the latest opinion: class voting can re-decide a track's
21818
- * class afterwards, and a group's composition is the history of who came
21819
- * together. A consumer counts these to badge a thumbnail — "two people and a
21820
- * dog" — rather than being handed a second, denormalised tally that would
21821
- * drift from the members it claims to describe.
21822
- */
21823
- className: string().nullable(),
21824
- /** `primary` is the one member that carries the group's identity. */
21825
- role: _enum([
21826
- "primary",
21827
- "sibling",
21828
- "child"
21829
- ]).nullable(),
21830
- joinedAt: number(),
21831
- /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
21832
- * at read time. Absent when nothing resolved, never an empty string. */
21833
- label: string().optional(),
21834
- /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
21835
- * recognised nobody, and absent for a member whose track has been pruned —
21836
- * a thumbnail that names the wrong person is worse than one naming nobody. */
21837
- subLabel: string().optional()
21838
- })).readonly()
21839
- });
21840
- /**
21841
- * What a LIST of groups carries: the envelope plus what it is MADE OF.
21842
- *
21843
- * Coarse on purpose — the operator's rule is "only the rough data on the list,
21844
- * we extend when we notice we need more". Enough to draw the card ("two people
21845
- * and a dog") and no more. The MEMBERS, their names and the per-member links
21846
- * are on {@link getSummary}: shipping every member of every group so a client
21847
- * can count them turns a page of two hundred groups into a thousand records to
21848
- * draw two hundred badges.
21849
- */
21850
- var SummaryListItemSchema = object({
21851
- summary: SummarySchema,
21852
- /** Class counts, most numerous first; `className: null` is a member whose
21853
- * class never resolved, counted so the counts add up to `memberCount`. */
21854
- classes: array(object({
21855
- className: string().nullable(),
21856
- count: number().int().positive()
21857
- })).readonly()
21858
- });
21859
- var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
21860
- /**
21861
- * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
21862
- *
21863
- * The reel on the cameras page and the Events gallery both ride a cursor, so a
21864
- * summaries feed that could only answer "the last N for these cameras"
21865
- * (`listSummaries`) would make groups available in the timeline and nowhere
21866
- * else. Two feeds with different ordering contracts would be two ideas of what
21867
- * "newest" means, on one screen.
21868
- */
21869
- var RecentSummariesQueryInput = object({
21870
- /** Devices to merge. An empty array yields an empty page. */
21871
- deviceIds: array(number()),
21872
- /** Window lower bound on `lastActiveAt` (inclusive). */
21873
- since: number().optional(),
21874
- /** Window upper bound on `lastActiveAt` (inclusive). */
21875
- until: number().optional(),
21876
- limit: number().int().min(1).max(500).default(100),
21877
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
21878
- cursor: string().optional(),
21879
- /**
21880
- * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
21881
- * deliberately the same name: the events filter tree emits one list of ticked
21882
- * taxonomy nodes, and a summaries feed that called it something else would
21883
- * make the operator's one filter component produce two shapes.
21884
- *
21885
- * A question about the MEMBERS: a group matches when ANY of them does. "Show
21886
- * me the arrivals with a dog" has to return the group of four people who had
21887
- * one with them; a filter on the group's own fields could only ever answer
21888
- * about its primary.
21889
- *
21890
- * Matched against all THREE tiers of a member — the class (`animal`), the
21891
- * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
21892
- * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
21893
- * an event kind in the tree and a tier-1 label on an `animal` track; a filter
21894
- * that read only the class would answer "animal" and never "dog".
21895
- *
21896
- * ABSENT or EMPTY means no filter — absent is not a selection of none.
21897
- */
21898
- classes: array(string().min(1).max(60)).max(40).optional()
21899
- });
21900
- var RecentSummariesPageSchema = object({
21901
- /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
21902
- * {@link listSummaries} — one list shape, so a card renders the same
21903
- * whichever feed drew it. */
21904
- summaries: array(SummaryListItemSchema).readonly(),
21905
- nextCursor: string().nullable()
21906
- });
21907
21898
  var RecentTracksPageSchema = object({
21908
21899
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
21909
21900
  tracks: array(TrackSchema).readonly(),
@@ -22415,7 +22406,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
22415
22406
  classes: array(string()).optional(),
22416
22407
  /** See {@link ExcludeSourcesDoc}. */
22417
22408
  excludeSources: array(TrackSourceSchema).optional()
22418
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
22409
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
22419
22410
  kind: "mutation",
22420
22411
  auth: "admin"
22421
22412
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -23635,6 +23626,23 @@ var MotionSourceEnum = _enum([
23635
23626
  */
23636
23627
  var MotionSourcesSchema = array(MotionSourceEnum);
23637
23628
  /**
23629
+ * The operator-facing name of each MOTION source (D672: `onboard` = the
23630
+ * camera's sensors — its own motion plus any sensor attached to it). The wire
23631
+ * value stays `onboard`; only the label changed. `detectionSources: 'onboard'`
23632
+ * ("Camera onboard AI") and the notification source filter keep their labels.
23633
+ */
23634
+ var MOTION_SOURCE_LABELS = {
23635
+ analyzer: "Frame-diff Analyzer (motion addon)",
23636
+ onboard: "Camera sensors",
23637
+ "device-activity": "Device activity (the device says it is working)"
23638
+ };
23639
+ /** The order the motion-source picker offers them in (not the enum's order). */
23640
+ var MOTION_SOURCE_PICKER_ORDER = [
23641
+ "analyzer",
23642
+ "onboard",
23643
+ "device-activity"
23644
+ ];
23645
+ /**
23638
23646
  * Which root detector a camera runs — EXACTLY ONE.
23639
23647
  *
23640
23648
  * Deliberately the SAME vocabulary post-analysis already tags every detection
@@ -23981,7 +23989,14 @@ var RunnerCameraConfigSchema = object({
23981
23989
  */
23982
23990
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
23983
23991
  });
23984
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
23992
+ MOTION_SOURCE_PICKER_ORDER.map((value) => value === "onboard" ? {
23993
+ value,
23994
+ label: MOTION_SOURCE_LABELS[value],
23995
+ description: "The camera's own motion, plus any sensor attached to it"
23996
+ } : {
23997
+ value,
23998
+ label: MOTION_SOURCE_LABELS[value]
23999
+ }), motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
23985
24000
  /**
23986
24001
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
23987
24002
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -24555,6 +24570,11 @@ var CameraStatusSchema = object({
24555
24570
  */
24556
24571
  switchedOff: array(CameraSwitchIdSchema).readonly(),
24557
24572
  /**
24573
+ * The camera's attached sensors (D672). Optional only for a status composed
24574
+ * by an orchestrator older than D672; this orchestrator always sets it.
24575
+ */
24576
+ cameraSensors: CameraSensorsStatusSchema.optional(),
24577
+ /**
24558
24578
  * Stages of the bounded fan-out that were CUT SHORT — a timeout or a
24559
24579
  * rejection — and whose block is therefore `null` because we could not
24560
24580
  * READ it, not because there is nothing there.
@@ -31893,7 +31913,9 @@ var MotionOnMotionChangedDataSchema = object({
31893
31913
  detected: boolean(),
31894
31914
  timestamp: number(),
31895
31915
  source: MotionSourceEnum,
31896
- regions: array(MotionRegionSchema).readonly().optional()
31916
+ regions: array(MotionRegionSchema).readonly().optional(),
31917
+ /** Who started it (D672). Absent = the camera itself. Only `onboard` carries `sensor`. */
31918
+ triggeredBy: MotionTriggeredBySchema.optional()
31897
31919
  });
31898
31920
  var motionCapability = {
31899
31921
  name: "motion",
@@ -45339,12 +45361,6 @@ Object.freeze({
45339
45361
  addonId: null,
45340
45362
  access: "view"
45341
45363
  },
45342
- "pipelineAnalytics.getSummary": {
45343
- capName: "pipeline-analytics",
45344
- capScope: "device",
45345
- addonId: null,
45346
- access: "view"
45347
- },
45348
45364
  "pipelineAnalytics.getTrack": {
45349
45365
  capName: "pipeline-analytics",
45350
45366
  capScope: "device",
@@ -45405,12 +45421,6 @@ Object.freeze({
45405
45421
  addonId: null,
45406
45422
  access: "view"
45407
45423
  },
45408
- "pipelineAnalytics.listRecentSummaries": {
45409
- capName: "pipeline-analytics",
45410
- capScope: "device",
45411
- addonId: null,
45412
- access: "view"
45413
- },
45414
45424
  "pipelineAnalytics.listRecentTracks": {
45415
45425
  capName: "pipeline-analytics",
45416
45426
  capScope: "device",
@@ -45441,12 +45451,6 @@ Object.freeze({
45441
45451
  addonId: null,
45442
45452
  access: "view"
45443
45453
  },
45444
- "pipelineAnalytics.listSummaries": {
45445
- capName: "pipeline-analytics",
45446
- capScope: "device",
45447
- addonId: null,
45448
- access: "view"
45449
- },
45450
45454
  "pipelineAnalytics.listTrackMedia": {
45451
45455
  capName: "pipeline-analytics",
45452
45456
  capScope: "device",
@@ -49616,11 +49620,6 @@ Object.freeze({
49616
49620
  form: "single",
49617
49621
  optional: true
49618
49622
  }],
49619
- "pipelineAnalytics.listRecentSummaries": [{
49620
- name: "deviceIds",
49621
- form: "array",
49622
- optional: false
49623
- }],
49624
49623
  "pipelineAnalytics.listRecentTracks": [{
49625
49624
  name: "deviceIds",
49626
49625
  form: "array",
@@ -49631,11 +49630,6 @@ Object.freeze({
49631
49630
  form: "array",
49632
49631
  optional: true
49633
49632
  }],
49634
- "pipelineAnalytics.listSummaries": [{
49635
- name: "deviceIds",
49636
- form: "array",
49637
- optional: false
49638
- }],
49639
49633
  "pipelineAnalytics.listTrackMedia": [{
49640
49634
  name: "deviceId",
49641
49635
  form: "single",
@@ -75143,6 +75137,20 @@ var COLD_MOTION = {
75143
75137
  lastDetectedAt: null,
75144
75138
  autoClearAfterMs: null
75145
75139
  };
75140
+ /**
75141
+ * The motion seed a constructor writes OVER the slice hydrated from the
75142
+ * persisted runtime state. The level is a placeholder (`false`) until the
75143
+ * CCU says otherwise, but a stored rise is a fact: `lastDetectedAt: null`
75144
+ * means "never detected" (`motion.cap.ts`), and a restart must not turn
75145
+ * "fired an hour ago" into that.
75146
+ */
75147
+ function coldMotionKeepingRise(stored) {
75148
+ const rise = stored?.lastDetectedAt;
75149
+ return {
75150
+ ...COLD_MOTION,
75151
+ lastDetectedAt: typeof rise === "number" && Number.isFinite(rise) && rise > 0 ? rise : null
75152
+ };
75153
+ }
75146
75154
  var COLD_CLIMATE = {
75147
75155
  mode: "auto",
75148
75156
  availableModes: [...[
@@ -76692,7 +76700,7 @@ var HmSensorDevice = class extends HmChildDevice {
76692
76700
  getStatus: async () => this.runtimeState.getCapState("motion") ?? COLD_MOTION,
76693
76701
  isDetected: async () => (this.runtimeState.getCapState("motion") ?? COLD_MOTION).detected
76694
76702
  });
76695
- this.runtimeState.setCapState("motion", COLD_MOTION);
76703
+ this.runtimeState.setCapState("motion", coldMotionKeepingRise(this.runtimeState.getCapState("motion")));
76696
76704
  }
76697
76705
  handleValueChanged(event, origin) {
76698
76706
  const now = event.ts || Date.now();
@@ -77729,4 +77737,4 @@ var HomematicProviderAddon = class extends BaseDeviceProvider {
77729
77737
  }
77730
77738
  };
77731
77739
  //#endregion
77732
- export { string as A, eventEmitterCapability as C, DeviceType as D, switchCapability as E, HomematicProviderAddon, createEvent as O, deviceAdminLinkCapability as S, motionCapability as T, toHomematicOptions as _, decodeClimate as a, climateControlCapability as b, toHmClimateMode as c, mapHmChannel as d, mapHmDeviceChannels as f, homematicConfigSchema as g, homematicAddonConfigSchema as h, registerTemperatureCap as i, EventCategory as j, object as k, deriveHmEntitySpecs as l, buildConnectionFormSchema as m, registerHumidityCap as n, decodeCover as o, homematicFacades as p, registerPowerMeterCap as r, decodeLock as s, registerAmbientLightCap as t, inferHmDeviceType as u, BaseDevice as v, lockControlCapability as w, coverCapability as x, buildDeviceAdminUrl as y };
77740
+ export { object as A, deviceAdminLinkCapability as C, switchCapability as D, motionCapability as E, HomematicProviderAddon, EventCategory as M, DeviceType as O, coverCapability as S, lockControlCapability as T, homematicConfigSchema as _, decodeClimate as a, buildDeviceAdminUrl as b, toHmClimateMode as c, inferHmDeviceType as d, mapHmChannel as f, homematicAddonConfigSchema as g, buildConnectionFormSchema as h, registerTemperatureCap as i, string as j, createEvent as k, deriveHmEntitySpecs as l, homematicFacades as m, registerHumidityCap as n, decodeCover as o, mapHmDeviceChannels as p, registerPowerMeterCap as r, decodeLock as s, registerAmbientLightCap as t, coldMotionKeepingRise as u, toHomematicOptions as v, eventEmitterCapability as w, climateControlCapability as x, BaseDevice as y };
package/dist/index.js CHANGED
@@ -395,7 +395,7 @@ var HomematicDevice = class extends require_addon.BaseDevice {
395
395
  getStatus: async () => this.runtimeState.getCapState("motion") ?? COLD_MOTION,
396
396
  isDetected: async () => (this.runtimeState.getCapState("motion") ?? COLD_MOTION).detected
397
397
  });
398
- this.runtimeState.setCapState("motion", COLD_MOTION);
398
+ this.runtimeState.setCapState("motion", require_addon.coldMotionKeepingRise(this.runtimeState.getCapState("motion")));
399
399
  }
400
400
  registerEventEmitterCap(keyChannels) {
401
401
  this.eventTypes = keyEventVocabulary(keyChannels);
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as string, C as eventEmitterCapability, D as DeviceType, E as switchCapability, HomematicProviderAddon, O as createEvent, S as deviceAdminLinkCapability, T as motionCapability, _ as toHomematicOptions, a as decodeClimate, b as climateControlCapability, c as toHmClimateMode, d as mapHmChannel, f as mapHmDeviceChannels, g as homematicConfigSchema, h as homematicAddonConfigSchema, i as registerTemperatureCap, j as EventCategory, k as object, l as deriveHmEntitySpecs, m as buildConnectionFormSchema, n as registerHumidityCap, o as decodeCover, p as homematicFacades, r as registerPowerMeterCap, s as decodeLock, t as registerAmbientLightCap, u as inferHmDeviceType, v as BaseDevice, w as lockControlCapability, x as coverCapability, y as buildDeviceAdminUrl } from "./addon.mjs";
1
+ import { A as object, C as deviceAdminLinkCapability, D as switchCapability, E as motionCapability, HomematicProviderAddon, M as EventCategory, O as DeviceType, S as coverCapability, T as lockControlCapability, _ as homematicConfigSchema, a as decodeClimate, b as buildDeviceAdminUrl, c as toHmClimateMode, d as inferHmDeviceType, f as mapHmChannel, g as homematicAddonConfigSchema, h as buildConnectionFormSchema, i as registerTemperatureCap, j as string, k as createEvent, l as deriveHmEntitySpecs, m as homematicFacades, n as registerHumidityCap, o as decodeCover, p as mapHmDeviceChannels, r as registerPowerMeterCap, s as decodeLock, t as registerAmbientLightCap, u as coldMotionKeepingRise, v as toHomematicOptions, w as eventEmitterCapability, x as climateControlCapability, y as BaseDevice } from "./addon.mjs";
2
2
  //#region src/homematic-device.ts
3
3
  /**
4
4
  * Persisted config every Homematic-backed device carries. `address` is
@@ -394,7 +394,7 @@ var HomematicDevice = class extends BaseDevice {
394
394
  getStatus: async () => this.runtimeState.getCapState("motion") ?? COLD_MOTION,
395
395
  isDetected: async () => (this.runtimeState.getCapState("motion") ?? COLD_MOTION).detected
396
396
  });
397
- this.runtimeState.setCapState("motion", COLD_MOTION);
397
+ this.runtimeState.setCapState("motion", coldMotionKeepingRise(this.runtimeState.getCapState("motion")));
398
398
  }
399
399
  registerEventEmitterCap(keyChannels) {
400
400
  this.eventTypes = keyEventVocabulary(keyChannels);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homematic",
3
- "version": "1.2.120",
3
+ "version": "1.2.121",
4
4
  "description": "Homematic / HomematicIP (CCU3 / RaspberryMatic) device-provider addon for CamStack — wraps the nodehomematic library",
5
5
  "keywords": [
6
6
  "camstack",