@camstack/addon-provider-homematic 1.2.102 → 1.2.103

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
@@ -8,7 +8,7 @@ let http = require("http");
8
8
  let crypto$1 = require("crypto");
9
9
  let fs_promises = require("fs/promises");
10
10
  let path = require("path");
11
- //#region ../types/dist/event-category-ZyX6jcse.mjs
11
+ //#region ../types/dist/event-category-BVDXG4tB.mjs
12
12
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
13
13
  EventCategory["SystemBoot"] = "system.boot";
14
14
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -625,6 +625,20 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
625
625
  * pull-reconcile from the provider's `getStatus` on reconnect. */
626
626
  EventCategory["MeshNetworkChanged"] = "network.mesh.changed";
627
627
  EventCategory["BackupCompleted"] = "backup.completed";
628
+ /**
629
+ * A whole backup RUN finished — every destination attempted, win or lose.
630
+ *
631
+ * `backup.completed` fires once per DESTINATION, which is the right grain for
632
+ * a progress UI and the wrong one for a notification: an operator with three
633
+ * destinations would be told three times. And a run where two of three
634
+ * destinations succeeded is not a clean success — a single "backup
635
+ * completed" that hid the failed one would be a lie, so the count of each is
636
+ * carried here and the message says both.
637
+ *
638
+ * Emitted by the backup orchestrator only after the destination loop, so a
639
+ * run that dies during the BUILD phase produces no completion at all.
640
+ */
641
+ EventCategory["BackupRunCompleted"] = "backup.run-completed";
628
642
  EventCategory["BackupRestored"] = "backup.restored";
629
643
  EventCategory["NotificationDispatched"] = "notification.dispatched";
630
644
  EventCategory["NotificationFailed"] = "notification.failed";
@@ -5355,7 +5369,7 @@ var ZodIssueCode = {
5355
5369
  var ZodFirstPartyTypeKind;
5356
5370
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5357
5371
  //#endregion
5358
- //#region ../types/dist/sleep-DBKu2-U5.mjs
5372
+ //#region ../types/dist/sleep-DEuj7E3j.mjs
5359
5373
  /**
5360
5374
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5361
5375
  * window to float samples (D455).
@@ -11548,6 +11562,72 @@ var brokerCapability = {
11548
11562
  }
11549
11563
  };
11550
11564
  DeviceType.Camera;
11565
+ /**
11566
+ * The signals a device can emit to WAKE its own stream.
11567
+ *
11568
+ * A camera whose stream is built on demand sleeps until something asks for it,
11569
+ * and "something" cannot be a consumer that is merely attached — a Frigate-style
11570
+ * puller holds a session open for ever, and treating that as demand would keep
11571
+ * a battery camera awake for ever, which is the whole thing the battery is for
11572
+ * (D173). So the wake has to come from the CAMERA: an event it noticed by
11573
+ * itself, with no stream running.
11574
+ *
11575
+ * ## The vocabulary is the PROVIDER'S, not ours
11576
+ *
11577
+ * Like `consumables`, this cap declares no vocabulary of its own. A provider
11578
+ * names each signal with a `code` it chooses and a `label` an operator reads.
11579
+ * Reolink offers motion and camera-native detection; another provider may offer
11580
+ * a tamper, a doorbell press, a PIR, or something no camera in this fleet has
11581
+ * yet. A fixed enum here would mean every new signal is a framework release.
11582
+ *
11583
+ * It is deliberately NOT derived from the caps a device already binds. Whether
11584
+ * a camera CAN push firmware motion is expressed by `motionSources` containing
11585
+ * `'onboard'`, and whether it does AI on-camera by the `native-object-detection`
11586
+ * binding — but both answer "what drives the detection pipeline", which is a
11587
+ * different question from "what may wake a sleeping stream". A camera can do
11588
+ * the first and not be trusted with the second, and the operator picks per
11589
+ * camera. Two questions, two authorities.
11590
+ *
11591
+ * ## Availability is not permission
11592
+ *
11593
+ * `listSignals` says what the device CAN emit. Whether a given signal actually
11594
+ * wakes the stream is the operator's per-camera choice, held by the broker
11595
+ * alongside the cooldown — see the stream-broker cap's wake settings. A
11596
+ * provider declaring a signal is not a provider enabling it.
11597
+ */
11598
+ /** One signal a device can emit. */
11599
+ var StreamSignalSchema = object({
11600
+ /** Stable id chosen by the provider, e.g. `'motion'`, `'person'`, `'tamper'`. */
11601
+ code: string().min(1),
11602
+ /** What an operator reads in the picker. The provider's own wording. */
11603
+ label: string().min(1),
11604
+ /**
11605
+ * Whether the provider recommends this signal ON when a camera is first set
11606
+ * up. A provider knows which of its signals are cheap and reliable; an
11607
+ * operator should not have to discover that by trial. Reolink recommends
11608
+ * both of its own.
11609
+ */
11610
+ recommended: boolean()
11611
+ });
11612
+ var StreamSignalsStatusSchema = object({
11613
+ signals: array(StreamSignalSchema),
11614
+ lastFetchedAt: number()
11615
+ });
11616
+ var streamSignalsCapability = {
11617
+ name: "stream-signals",
11618
+ scope: "device",
11619
+ deviceNative: true,
11620
+ mode: "singleton",
11621
+ deviceTypes: Object.values(DeviceType),
11622
+ runtimeState: StreamSignalsStatusSchema,
11623
+ methods: {
11624
+ /**
11625
+ * What this device can emit. Empty is a valid and common answer — most
11626
+ * cameras have nothing to offer here, and an empty list is what makes the
11627
+ * broker's picker show nothing rather than a false choice.
11628
+ */
11629
+ listSignals: method(_void(), array(StreamSignalSchema).readonly()) }
11630
+ };
11551
11631
  /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
11552
11632
  var StreamFormatSchema = _enum([
11553
11633
  "webrtc",
@@ -11944,6 +12024,22 @@ var EgressTranscodeSchema = object({
11944
12024
  camStreamId: string().nullable()
11945
12025
  });
11946
12026
  method(object({
12027
+ deviceId: number().int().nonnegative(),
12028
+ /** The provider's signal code. */
12029
+ code: string().min(1),
12030
+ /** Ms epoch. Absent ⇒ now. */
12031
+ at: number().optional()
12032
+ }), object({
12033
+ /** Whether the broker acted on it, and if not, why. */
12034
+ accepted: boolean(),
12035
+ reason: _enum([
12036
+ "woke",
12037
+ "hold-extended",
12038
+ "not-enabled",
12039
+ "no-consumer",
12040
+ "unknown-code"
12041
+ ])
12042
+ }), { kind: "mutation" }), method(object({
11947
12043
  deviceId: number().int().nonnegative(),
11948
12044
  camStreamId: string().min(1),
11949
12045
  kind: CamStreamKindSchema,
@@ -12198,6 +12294,16 @@ var PickStreamRequirementsSchema = object({
12198
12294
  acceptCodecs: array(StreamCodecSchema).readonly().optional(),
12199
12295
  /** Minimum vertical resolution. Streams shorter than this are dropped. */
12200
12296
  minHeight: number().int().positive().optional(),
12297
+ /**
12298
+ * Maximum vertical resolution. Streams TALLER than this are dropped.
12299
+ *
12300
+ * A consumer can have a ceiling as real as its floor: Alexa documents
12301
+ * 480p to 1080p, and a 4K stream is as unusable to an Echo as a 360p one.
12302
+ * Without this the ceiling had to be re-implemented by every caller — and
12303
+ * one caller implementing it privately is how a second scoring authority
12304
+ * gets born.
12305
+ */
12306
+ maxHeight: number().int().positive().optional(),
12201
12307
  /** Minimum horizontal resolution. */
12202
12308
  minWidth: number().int().positive().optional(),
12203
12309
  /**
@@ -12214,7 +12320,22 @@ var PickStreamRequirementsSchema = object({
12214
12320
  * transcoded" guard: if the device is already serving the consumer's
12215
12321
  * codec end-to-end, there's nothing to optimise.
12216
12322
  */
12217
- requireSiblingCodec: array(StreamCodecSchema).readonly().optional()
12323
+ requireSiblingCodec: array(StreamCodecSchema).readonly().optional(),
12324
+ /**
12325
+ * Whether a stream the consumer CANNOT decode may still be picked, on the
12326
+ * understanding that it will be transcoded.
12327
+ *
12328
+ * Default `false` — today's behaviour, and the right one for a bypass
12329
+ * question ("is there a stream I can forward untouched?"). Set `true` to
12330
+ * ask the larger question: "what is the best stream for me, transcoding if
12331
+ * I must?" A stream that satisfies `acceptCodecs` always outranks one that
12332
+ * does not, so a passthrough is never lost to a transcode; the answer says
12333
+ * which it is in {@link PickedCamStreamSchema.transcodes}.
12334
+ *
12335
+ * This is what lets one picker serve both the bypass and the full source
12336
+ * choice, instead of a consumer scoring privately when the bypass misses.
12337
+ */
12338
+ allowTranscode: boolean().optional()
12218
12339
  }).readonly();
12219
12340
  var PickStreamPreferencesSchema = object({
12220
12341
  /**
@@ -12228,12 +12349,32 @@ var PickStreamPreferencesSchema = object({
12228
12349
  * picks the tallest stream; `'lowest'` picks the shortest (used by
12229
12350
  * memory-constrained consumers / Apple Home guest sessions).
12230
12351
  */
12231
- resolutionPreference: _enum(["highest", "lowest"]).optional()
12352
+ resolutionPreference: _enum(["highest", "lowest"]).optional(),
12353
+ /**
12354
+ * The height the consumer actually wants to DELIVER.
12355
+ *
12356
+ * Not a constraint — an ordering. With it set, the SMALLEST stream at or
12357
+ * above the target wins, and only if nothing reaches it does the tallest
12358
+ * take over. Pulling 1296 lines to draw 720 on a 1280x800 Echo panel costs
12359
+ * a decode and buys nothing, and `resolutionPreference: 'highest'` cannot
12360
+ * express that: it says "as big as possible", which is a different wish.
12361
+ *
12362
+ * Ignored when absent, so every existing caller keeps its ordering.
12363
+ */
12364
+ targetHeight: number().int().positive().optional()
12232
12365
  }).readonly();
12233
12366
  var PickedCamStreamSchema = object({
12234
12367
  camStreamId: string(),
12235
12368
  codec: string().optional(),
12236
12369
  resolution: CamStreamResolutionSchema.optional(),
12370
+ /**
12371
+ * Whether serving this stream requires a decode + re-encode.
12372
+ *
12373
+ * `false` is a stream the consumer can take as it stands. Only ever `true`
12374
+ * when the caller asked for it with `allowTranscode`, so a caller that did
12375
+ * not ask cannot be handed a cost it never agreed to pay.
12376
+ */
12377
+ transcodes: boolean(),
12237
12378
  /** One-line explanation of why this stream won — for logs / debug UI. */
12238
12379
  reason: string()
12239
12380
  });
@@ -16767,6 +16908,8 @@ var NcSystemEventKindSchema = _enum([
16767
16908
  "device-enabled",
16768
16909
  "device-battery-low",
16769
16910
  "device-battery-normal",
16911
+ "device-consumable-low",
16912
+ "device-consumable-normal",
16770
16913
  "stream-online",
16771
16914
  "stream-offline",
16772
16915
  "node-online",
@@ -16785,6 +16928,7 @@ var NcSystemEventKindSchema = _enum([
16785
16928
  "addon-updated",
16786
16929
  "server-updated",
16787
16930
  "export-completed",
16931
+ "backup-completed",
16788
16932
  "camera-online",
16789
16933
  "camera-offline",
16790
16934
  "camera-disabled",
@@ -24066,10 +24210,28 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
24066
24210
  }), boolean()), method(object({
24067
24211
  deviceId: number().int().nonnegative(),
24068
24212
  sessionId: string()
24069
- }), object({ pendingRenegotiation: object({
24070
- target: WebrtcStreamTargetSchema,
24071
- epoch: number()
24072
- }).nullable() }));
24213
+ }), object({
24214
+ pendingRenegotiation: object({
24215
+ target: WebrtcStreamTargetSchema,
24216
+ epoch: number()
24217
+ }).nullable(),
24218
+ /**
24219
+ * Whether the session still EXISTS.
24220
+ *
24221
+ * A consumer that holds a resource for the life of a session needs to
24222
+ * be able to ask, because a session does not always end the way it
24223
+ * began. Measured on this hub 2026-09-13: an Echo that got stuck never
24224
+ * sent `SessionDisconnected`, so the Alexa exporter's
24225
+ * `releaseEgressTranscode` never ran, and a 2304x1296 HEVC to 720p
24226
+ * H.264 transcode kept running for NOBODY for more than twenty
24227
+ * minutes. The WebRTC session had logged `WebRTC session closed`
24228
+ * minutes earlier — the broker knew; the holder had no way to ask.
24229
+ *
24230
+ * `false` for a session id the provider has never heard of, which is
24231
+ * the same answer as "it ended": either way nothing is holding it up.
24232
+ */
24233
+ alive: boolean()
24234
+ }));
24073
24235
  object({
24074
24236
  /** All accessory children of the parent. */
24075
24237
  childDeviceIds: array(number()).readonly(),
@@ -33988,6 +34150,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
33988
34150
  smoke: smokeCapability,
33989
34151
  streamCatalog: streamCatalogCapability,
33990
34152
  streamParams: streamParamsCapability,
34153
+ streamSignals: streamSignalsCapability,
33991
34154
  switch: switchCapability,
33992
34155
  tamper: tamperCapability,
33993
34156
  temperatureSensor: temperatureSensorCapability,
@@ -40561,6 +40724,12 @@ Object.freeze({
40561
40724
  addonId: null,
40562
40725
  access: "create"
40563
40726
  },
40727
+ "streamBroker.reportStreamSignal": {
40728
+ capName: "stream-broker",
40729
+ capScope: "system",
40730
+ addonId: null,
40731
+ access: "create"
40732
+ },
40564
40733
  "streamBroker.restartProfile": {
40565
40734
  capName: "stream-broker",
40566
40735
  capScope: "system",
@@ -40645,6 +40814,12 @@ Object.freeze({
40645
40814
  addonId: null,
40646
40815
  access: "create"
40647
40816
  },
40817
+ "streamSignals.listSignals": {
40818
+ capName: "stream-signals",
40819
+ capScope: "device",
40820
+ addonId: null,
40821
+ access: "view"
40822
+ },
40648
40823
  "switch.setState": {
40649
40824
  capName: "switch",
40650
40825
  capScope: "device",
@@ -43017,6 +43192,11 @@ Object.freeze({
43017
43192
  form: "single",
43018
43193
  optional: false
43019
43194
  }],
43195
+ "streamBroker.reportStreamSignal": [{
43196
+ name: "deviceId",
43197
+ form: "single",
43198
+ optional: false
43199
+ }],
43020
43200
  "streamBroker.restartProfile": [{
43021
43201
  name: "deviceId",
43022
43202
  form: "single",
package/dist/addon.mjs CHANGED
@@ -9,7 +9,7 @@ import { join } from "path";
9
9
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
10
10
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
11
11
  //#endregion
12
- //#region ../types/dist/event-category-ZyX6jcse.mjs
12
+ //#region ../types/dist/event-category-BVDXG4tB.mjs
13
13
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
14
14
  EventCategory["SystemBoot"] = "system.boot";
15
15
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -626,6 +626,20 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
626
626
  * pull-reconcile from the provider's `getStatus` on reconnect. */
627
627
  EventCategory["MeshNetworkChanged"] = "network.mesh.changed";
628
628
  EventCategory["BackupCompleted"] = "backup.completed";
629
+ /**
630
+ * A whole backup RUN finished — every destination attempted, win or lose.
631
+ *
632
+ * `backup.completed` fires once per DESTINATION, which is the right grain for
633
+ * a progress UI and the wrong one for a notification: an operator with three
634
+ * destinations would be told three times. And a run where two of three
635
+ * destinations succeeded is not a clean success — a single "backup
636
+ * completed" that hid the failed one would be a lie, so the count of each is
637
+ * carried here and the message says both.
638
+ *
639
+ * Emitted by the backup orchestrator only after the destination loop, so a
640
+ * run that dies during the BUILD phase produces no completion at all.
641
+ */
642
+ EventCategory["BackupRunCompleted"] = "backup.run-completed";
629
643
  EventCategory["BackupRestored"] = "backup.restored";
630
644
  EventCategory["NotificationDispatched"] = "notification.dispatched";
631
645
  EventCategory["NotificationFailed"] = "notification.failed";
@@ -5356,7 +5370,7 @@ var ZodIssueCode = {
5356
5370
  var ZodFirstPartyTypeKind;
5357
5371
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5358
5372
  //#endregion
5359
- //#region ../types/dist/sleep-DBKu2-U5.mjs
5373
+ //#region ../types/dist/sleep-DEuj7E3j.mjs
5360
5374
  /**
5361
5375
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5362
5376
  * window to float samples (D455).
@@ -11549,6 +11563,72 @@ var brokerCapability = {
11549
11563
  }
11550
11564
  };
11551
11565
  DeviceType.Camera;
11566
+ /**
11567
+ * The signals a device can emit to WAKE its own stream.
11568
+ *
11569
+ * A camera whose stream is built on demand sleeps until something asks for it,
11570
+ * and "something" cannot be a consumer that is merely attached — a Frigate-style
11571
+ * puller holds a session open for ever, and treating that as demand would keep
11572
+ * a battery camera awake for ever, which is the whole thing the battery is for
11573
+ * (D173). So the wake has to come from the CAMERA: an event it noticed by
11574
+ * itself, with no stream running.
11575
+ *
11576
+ * ## The vocabulary is the PROVIDER'S, not ours
11577
+ *
11578
+ * Like `consumables`, this cap declares no vocabulary of its own. A provider
11579
+ * names each signal with a `code` it chooses and a `label` an operator reads.
11580
+ * Reolink offers motion and camera-native detection; another provider may offer
11581
+ * a tamper, a doorbell press, a PIR, or something no camera in this fleet has
11582
+ * yet. A fixed enum here would mean every new signal is a framework release.
11583
+ *
11584
+ * It is deliberately NOT derived from the caps a device already binds. Whether
11585
+ * a camera CAN push firmware motion is expressed by `motionSources` containing
11586
+ * `'onboard'`, and whether it does AI on-camera by the `native-object-detection`
11587
+ * binding — but both answer "what drives the detection pipeline", which is a
11588
+ * different question from "what may wake a sleeping stream". A camera can do
11589
+ * the first and not be trusted with the second, and the operator picks per
11590
+ * camera. Two questions, two authorities.
11591
+ *
11592
+ * ## Availability is not permission
11593
+ *
11594
+ * `listSignals` says what the device CAN emit. Whether a given signal actually
11595
+ * wakes the stream is the operator's per-camera choice, held by the broker
11596
+ * alongside the cooldown — see the stream-broker cap's wake settings. A
11597
+ * provider declaring a signal is not a provider enabling it.
11598
+ */
11599
+ /** One signal a device can emit. */
11600
+ var StreamSignalSchema = object({
11601
+ /** Stable id chosen by the provider, e.g. `'motion'`, `'person'`, `'tamper'`. */
11602
+ code: string().min(1),
11603
+ /** What an operator reads in the picker. The provider's own wording. */
11604
+ label: string().min(1),
11605
+ /**
11606
+ * Whether the provider recommends this signal ON when a camera is first set
11607
+ * up. A provider knows which of its signals are cheap and reliable; an
11608
+ * operator should not have to discover that by trial. Reolink recommends
11609
+ * both of its own.
11610
+ */
11611
+ recommended: boolean()
11612
+ });
11613
+ var StreamSignalsStatusSchema = object({
11614
+ signals: array(StreamSignalSchema),
11615
+ lastFetchedAt: number()
11616
+ });
11617
+ var streamSignalsCapability = {
11618
+ name: "stream-signals",
11619
+ scope: "device",
11620
+ deviceNative: true,
11621
+ mode: "singleton",
11622
+ deviceTypes: Object.values(DeviceType),
11623
+ runtimeState: StreamSignalsStatusSchema,
11624
+ methods: {
11625
+ /**
11626
+ * What this device can emit. Empty is a valid and common answer — most
11627
+ * cameras have nothing to offer here, and an empty list is what makes the
11628
+ * broker's picker show nothing rather than a false choice.
11629
+ */
11630
+ listSignals: method(_void(), array(StreamSignalSchema).readonly()) }
11631
+ };
11552
11632
  /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
11553
11633
  var StreamFormatSchema = _enum([
11554
11634
  "webrtc",
@@ -11945,6 +12025,22 @@ var EgressTranscodeSchema = object({
11945
12025
  camStreamId: string().nullable()
11946
12026
  });
11947
12027
  method(object({
12028
+ deviceId: number().int().nonnegative(),
12029
+ /** The provider's signal code. */
12030
+ code: string().min(1),
12031
+ /** Ms epoch. Absent ⇒ now. */
12032
+ at: number().optional()
12033
+ }), object({
12034
+ /** Whether the broker acted on it, and if not, why. */
12035
+ accepted: boolean(),
12036
+ reason: _enum([
12037
+ "woke",
12038
+ "hold-extended",
12039
+ "not-enabled",
12040
+ "no-consumer",
12041
+ "unknown-code"
12042
+ ])
12043
+ }), { kind: "mutation" }), method(object({
11948
12044
  deviceId: number().int().nonnegative(),
11949
12045
  camStreamId: string().min(1),
11950
12046
  kind: CamStreamKindSchema,
@@ -12199,6 +12295,16 @@ var PickStreamRequirementsSchema = object({
12199
12295
  acceptCodecs: array(StreamCodecSchema).readonly().optional(),
12200
12296
  /** Minimum vertical resolution. Streams shorter than this are dropped. */
12201
12297
  minHeight: number().int().positive().optional(),
12298
+ /**
12299
+ * Maximum vertical resolution. Streams TALLER than this are dropped.
12300
+ *
12301
+ * A consumer can have a ceiling as real as its floor: Alexa documents
12302
+ * 480p to 1080p, and a 4K stream is as unusable to an Echo as a 360p one.
12303
+ * Without this the ceiling had to be re-implemented by every caller — and
12304
+ * one caller implementing it privately is how a second scoring authority
12305
+ * gets born.
12306
+ */
12307
+ maxHeight: number().int().positive().optional(),
12202
12308
  /** Minimum horizontal resolution. */
12203
12309
  minWidth: number().int().positive().optional(),
12204
12310
  /**
@@ -12215,7 +12321,22 @@ var PickStreamRequirementsSchema = object({
12215
12321
  * transcoded" guard: if the device is already serving the consumer's
12216
12322
  * codec end-to-end, there's nothing to optimise.
12217
12323
  */
12218
- requireSiblingCodec: array(StreamCodecSchema).readonly().optional()
12324
+ requireSiblingCodec: array(StreamCodecSchema).readonly().optional(),
12325
+ /**
12326
+ * Whether a stream the consumer CANNOT decode may still be picked, on the
12327
+ * understanding that it will be transcoded.
12328
+ *
12329
+ * Default `false` — today's behaviour, and the right one for a bypass
12330
+ * question ("is there a stream I can forward untouched?"). Set `true` to
12331
+ * ask the larger question: "what is the best stream for me, transcoding if
12332
+ * I must?" A stream that satisfies `acceptCodecs` always outranks one that
12333
+ * does not, so a passthrough is never lost to a transcode; the answer says
12334
+ * which it is in {@link PickedCamStreamSchema.transcodes}.
12335
+ *
12336
+ * This is what lets one picker serve both the bypass and the full source
12337
+ * choice, instead of a consumer scoring privately when the bypass misses.
12338
+ */
12339
+ allowTranscode: boolean().optional()
12219
12340
  }).readonly();
12220
12341
  var PickStreamPreferencesSchema = object({
12221
12342
  /**
@@ -12229,12 +12350,32 @@ var PickStreamPreferencesSchema = object({
12229
12350
  * picks the tallest stream; `'lowest'` picks the shortest (used by
12230
12351
  * memory-constrained consumers / Apple Home guest sessions).
12231
12352
  */
12232
- resolutionPreference: _enum(["highest", "lowest"]).optional()
12353
+ resolutionPreference: _enum(["highest", "lowest"]).optional(),
12354
+ /**
12355
+ * The height the consumer actually wants to DELIVER.
12356
+ *
12357
+ * Not a constraint — an ordering. With it set, the SMALLEST stream at or
12358
+ * above the target wins, and only if nothing reaches it does the tallest
12359
+ * take over. Pulling 1296 lines to draw 720 on a 1280x800 Echo panel costs
12360
+ * a decode and buys nothing, and `resolutionPreference: 'highest'` cannot
12361
+ * express that: it says "as big as possible", which is a different wish.
12362
+ *
12363
+ * Ignored when absent, so every existing caller keeps its ordering.
12364
+ */
12365
+ targetHeight: number().int().positive().optional()
12233
12366
  }).readonly();
12234
12367
  var PickedCamStreamSchema = object({
12235
12368
  camStreamId: string(),
12236
12369
  codec: string().optional(),
12237
12370
  resolution: CamStreamResolutionSchema.optional(),
12371
+ /**
12372
+ * Whether serving this stream requires a decode + re-encode.
12373
+ *
12374
+ * `false` is a stream the consumer can take as it stands. Only ever `true`
12375
+ * when the caller asked for it with `allowTranscode`, so a caller that did
12376
+ * not ask cannot be handed a cost it never agreed to pay.
12377
+ */
12378
+ transcodes: boolean(),
12238
12379
  /** One-line explanation of why this stream won — for logs / debug UI. */
12239
12380
  reason: string()
12240
12381
  });
@@ -16768,6 +16909,8 @@ var NcSystemEventKindSchema = _enum([
16768
16909
  "device-enabled",
16769
16910
  "device-battery-low",
16770
16911
  "device-battery-normal",
16912
+ "device-consumable-low",
16913
+ "device-consumable-normal",
16771
16914
  "stream-online",
16772
16915
  "stream-offline",
16773
16916
  "node-online",
@@ -16786,6 +16929,7 @@ var NcSystemEventKindSchema = _enum([
16786
16929
  "addon-updated",
16787
16930
  "server-updated",
16788
16931
  "export-completed",
16932
+ "backup-completed",
16789
16933
  "camera-online",
16790
16934
  "camera-offline",
16791
16935
  "camera-disabled",
@@ -24067,10 +24211,28 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
24067
24211
  }), boolean()), method(object({
24068
24212
  deviceId: number().int().nonnegative(),
24069
24213
  sessionId: string()
24070
- }), object({ pendingRenegotiation: object({
24071
- target: WebrtcStreamTargetSchema,
24072
- epoch: number()
24073
- }).nullable() }));
24214
+ }), object({
24215
+ pendingRenegotiation: object({
24216
+ target: WebrtcStreamTargetSchema,
24217
+ epoch: number()
24218
+ }).nullable(),
24219
+ /**
24220
+ * Whether the session still EXISTS.
24221
+ *
24222
+ * A consumer that holds a resource for the life of a session needs to
24223
+ * be able to ask, because a session does not always end the way it
24224
+ * began. Measured on this hub 2026-09-13: an Echo that got stuck never
24225
+ * sent `SessionDisconnected`, so the Alexa exporter's
24226
+ * `releaseEgressTranscode` never ran, and a 2304x1296 HEVC to 720p
24227
+ * H.264 transcode kept running for NOBODY for more than twenty
24228
+ * minutes. The WebRTC session had logged `WebRTC session closed`
24229
+ * minutes earlier — the broker knew; the holder had no way to ask.
24230
+ *
24231
+ * `false` for a session id the provider has never heard of, which is
24232
+ * the same answer as "it ended": either way nothing is holding it up.
24233
+ */
24234
+ alive: boolean()
24235
+ }));
24074
24236
  object({
24075
24237
  /** All accessory children of the parent. */
24076
24238
  childDeviceIds: array(number()).readonly(),
@@ -33989,6 +34151,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
33989
34151
  smoke: smokeCapability,
33990
34152
  streamCatalog: streamCatalogCapability,
33991
34153
  streamParams: streamParamsCapability,
34154
+ streamSignals: streamSignalsCapability,
33992
34155
  switch: switchCapability,
33993
34156
  tamper: tamperCapability,
33994
34157
  temperatureSensor: temperatureSensorCapability,
@@ -40562,6 +40725,12 @@ Object.freeze({
40562
40725
  addonId: null,
40563
40726
  access: "create"
40564
40727
  },
40728
+ "streamBroker.reportStreamSignal": {
40729
+ capName: "stream-broker",
40730
+ capScope: "system",
40731
+ addonId: null,
40732
+ access: "create"
40733
+ },
40565
40734
  "streamBroker.restartProfile": {
40566
40735
  capName: "stream-broker",
40567
40736
  capScope: "system",
@@ -40646,6 +40815,12 @@ Object.freeze({
40646
40815
  addonId: null,
40647
40816
  access: "create"
40648
40817
  },
40818
+ "streamSignals.listSignals": {
40819
+ capName: "stream-signals",
40820
+ capScope: "device",
40821
+ addonId: null,
40822
+ access: "view"
40823
+ },
40649
40824
  "switch.setState": {
40650
40825
  capName: "switch",
40651
40826
  capScope: "device",
@@ -43018,6 +43193,11 @@ Object.freeze({
43018
43193
  form: "single",
43019
43194
  optional: false
43020
43195
  }],
43196
+ "streamBroker.reportStreamSignal": [{
43197
+ name: "deviceId",
43198
+ form: "single",
43199
+ optional: false
43200
+ }],
43021
43201
  "streamBroker.restartProfile": [{
43022
43202
  name: "deviceId",
43023
43203
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homematic",
3
- "version": "1.2.102",
3
+ "version": "1.2.103",
4
4
  "description": "Homematic / HomematicIP (CCU3 / RaspberryMatic) device-provider addon for CamStack — wraps the nodehomematic library",
5
5
  "keywords": [
6
6
  "camstack",