@riddix/hamh 2.1.0-alpha.815 → 2.1.0-alpha.816

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.
@@ -132609,6 +132609,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
132609
132609
  batteryEntity: config11.batteryEntity,
132610
132610
  roomEntities: config11.roomEntities,
132611
132611
  disableLockPin: config11.disableLockPin,
132612
+ lockUsercodeService: config11.lockUsercodeService,
132613
+ lockUsercodeSlot: config11.lockUsercodeSlot,
132612
132614
  powerEntity: config11.powerEntity,
132613
132615
  energyEntity: config11.energyEntity,
132614
132616
  suctionLevelEntity: config11.suctionLevelEntity,
@@ -132760,6 +132762,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
132760
132762
  batteryEntity: config11.batteryEntity,
132761
132763
  roomEntities: config11.roomEntities,
132762
132764
  disableLockPin: config11.disableLockPin,
132765
+ lockUsercodeService: config11.lockUsercodeService,
132766
+ lockUsercodeSlot: config11.lockUsercodeSlot,
132763
132767
  powerEntity: config11.powerEntity,
132764
132768
  energyEntity: config11.energyEntity,
132765
132769
  suctionLevelEntity: config11.suctionLevelEntity,
@@ -133602,6 +133606,8 @@ function entityMappingApi(mappingStorage) {
133602
133606
  chargingStateEntity: body.chargingStateEntity,
133603
133607
  roomEntities: body.roomEntities,
133604
133608
  disableLockPin: body.disableLockPin,
133609
+ lockUsercodeService: body.lockUsercodeService,
133610
+ lockUsercodeSlot: body.lockUsercodeSlot,
133605
133611
  powerEntity: body.powerEntity,
133606
133612
  energyEntity: body.energyEntity,
133607
133613
  suctionLevelEntity: body.suctionLevelEntity,
@@ -134092,6 +134098,8 @@ function configToProfileEntry(config11) {
134092
134098
  batteryEntity: config11.batteryEntity,
134093
134099
  roomEntities: config11.roomEntities,
134094
134100
  disableLockPin: config11.disableLockPin,
134101
+ lockUsercodeService: config11.lockUsercodeService,
134102
+ lockUsercodeSlot: config11.lockUsercodeSlot,
134095
134103
  powerEntity: config11.powerEntity,
134096
134104
  energyEntity: config11.energyEntity,
134097
134105
  suctionLevelEntity: config11.suctionLevelEntity,
@@ -134221,6 +134229,8 @@ function mappingProfileApi(mappingStorage) {
134221
134229
  batteryEntity: entry.batteryEntity,
134222
134230
  roomEntities: entry.roomEntities,
134223
134231
  disableLockPin: entry.disableLockPin,
134232
+ lockUsercodeService: entry.lockUsercodeService,
134233
+ lockUsercodeSlot: entry.lockUsercodeSlot,
134224
134234
  powerEntity: entry.powerEntity,
134225
134235
  energyEntity: entry.energyEntity,
134226
134236
  suctionLevelEntity: entry.suctionLevelEntity,
@@ -138410,6 +138420,8 @@ var EntityMappingStorage = class extends Service {
138410
138420
  chargingStateEntity: request.chargingStateEntity?.trim() || void 0,
138411
138421
  roomEntities: roomEntities.length > 0 ? roomEntities : void 0,
138412
138422
  disableLockPin: request.disableLockPin || void 0,
138423
+ lockUsercodeService: request.lockUsercodeService?.trim() || void 0,
138424
+ lockUsercodeSlot: sanitizeUsercodeSlot(request.lockUsercodeSlot),
138413
138425
  powerEntity: request.powerEntity?.trim() || void 0,
138414
138426
  energyEntity: request.energyEntity?.trim() || void 0,
138415
138427
  pressureEntity: request.pressureEntity?.trim() || void 0,
@@ -138439,7 +138451,7 @@ var EntityMappingStorage = class extends Service {
138439
138451
  climateAutoMode: request.climateAutoMode || void 0,
138440
138452
  composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0
138441
138453
  };
138442
- if (!config11.matterDeviceType && !config11.customName && !config11.customProductName && !config11.customVendorName && !config11.customSerialNumber && config11.customVendorId === void 0 && config11.disabled !== true && !config11.filterLifeEntity && !config11.cleaningModeEntity && !config11.temperatureEntity && !config11.humidityEntity && !config11.batteryEntity && !config11.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.powerEntity && !config11.energyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && (!config11.fanWindPresets || (config11.fanWindPresets.natural?.length ?? 0) === 0 && (config11.fanWindPresets.sleep?.length ?? 0) === 0) && !config11.fanRestoreSpeedOnPowerOn && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.selectExposeAsSwitch && !config11.selectSwitchOnOption && !config11.selectSwitchOffOption && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0)) {
138454
+ if (!config11.matterDeviceType && !config11.customName && !config11.customProductName && !config11.customVendorName && !config11.customSerialNumber && config11.customVendorId === void 0 && config11.disabled !== true && !config11.filterLifeEntity && !config11.cleaningModeEntity && !config11.temperatureEntity && !config11.humidityEntity && !config11.batteryEntity && !config11.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.lockUsercodeService && config11.lockUsercodeSlot === void 0 && !config11.powerEntity && !config11.energyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && (!config11.fanWindPresets || (config11.fanWindPresets.natural?.length ?? 0) === 0 && (config11.fanWindPresets.sleep?.length ?? 0) === 0) && !config11.fanRestoreSpeedOnPowerOn && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.selectExposeAsSwitch && !config11.selectSwitchOnOption && !config11.selectSwitchOffOption && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0)) {
138443
138455
  bridgeMap.delete(request.entityId);
138444
138456
  } else {
138445
138457
  bridgeMap.set(request.entityId, config11);
@@ -138469,6 +138481,16 @@ function sanitizeVendorId(value) {
138469
138481
  }
138470
138482
  return n;
138471
138483
  }
138484
+ function sanitizeUsercodeSlot(value) {
138485
+ if (value === void 0 || value === null || value === "") {
138486
+ return void 0;
138487
+ }
138488
+ const n = typeof value === "string" ? Number(value) : value;
138489
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
138490
+ return void 0;
138491
+ }
138492
+ return n;
138493
+ }
138472
138494
  function sanitizeDebounceMs(value) {
138473
138495
  if (value === void 0 || value === null || value === "") {
138474
138496
  return void 0;
@@ -164176,6 +164198,27 @@ function normalizeSupportedIndex(index) {
164176
164198
  }
164177
164199
  return null;
164178
164200
  }
164201
+ function buildUsercodeSetAction(service, slot, pin) {
164202
+ const pinKey = service.split(".")[0] === "zha" ? "user_code" : "usercode";
164203
+ return { action: service, data: { code_slot: slot, [pinKey]: pin } };
164204
+ }
164205
+ function buildUsercodeClearAction(service, slot) {
164206
+ return {
164207
+ action: service.replace(".set_", ".clear_"),
164208
+ data: { code_slot: slot }
164209
+ };
164210
+ }
164211
+ function usercodePassthroughFrom(homeAssistant) {
164212
+ const service = homeAssistant.state.mapping?.lockUsercodeService?.trim();
164213
+ if (!service) {
164214
+ return void 0;
164215
+ }
164216
+ return {
164217
+ service,
164218
+ slot: homeAssistant.state.mapping?.lockUsercodeSlot ?? 1,
164219
+ callAction: (action) => homeAssistant.callAction(action)
164220
+ };
164221
+ }
164179
164222
  function asFabricIndex(value) {
164180
164223
  return value === void 0 || value === 0 ? null : FabricIndex3(value);
164181
164224
  }
@@ -164266,7 +164309,7 @@ function buildGetCredentialStatusResponse(env, entityId, request) {
164266
164309
  nextCredentialIndex: null
164267
164310
  };
164268
164311
  }
164269
- async function applySetCredential(env, entityId, request, fabricIndex) {
164312
+ async function applySetCredential(env, entityId, request, fabricIndex, passthrough) {
164270
164313
  if (request.credential.credentialType !== DoorLock3.CredentialType.Pin || normalizeSupportedIndex(request.credential.credentialIndex) === null) {
164271
164314
  return {
164272
164315
  status: Status2.Failure,
@@ -164292,6 +164335,9 @@ async function applySetCredential(env, entityId, request, fabricIndex) {
164292
164335
  lastModifiedFabricIndex: fabricIndex,
164293
164336
  creatorFabricIndex: fabricIndex
164294
164337
  });
164338
+ passthrough?.callAction(
164339
+ buildUsercodeSetAction(passthrough.service, passthrough.slot, pinCode)
164340
+ );
164295
164341
  }
164296
164342
  return {
164297
164343
  status: Status2.Success,
@@ -164311,15 +164357,35 @@ async function applySetUser(env, entityId, request, fabricIndex) {
164311
164357
  fabricIndex
164312
164358
  });
164313
164359
  }
164314
- async function applyClearCredential(env, entityId, request) {
164360
+ async function applyClearCredential(env, entityId, request, passthrough) {
164315
164361
  if (request.credential === null) {
164316
164362
  const storage2 = env.get(LockCredentialStorage);
164317
164363
  await storage2.deleteCredential(entityId);
164364
+ passthrough?.callAction(
164365
+ buildUsercodeClearAction(passthrough.service, passthrough.slot)
164366
+ );
164318
164367
  return;
164319
164368
  }
164320
164369
  if (request.credential.credentialType === DoorLock3.CredentialType.Pin && normalizeSupportedIndex(request.credential.credentialIndex) !== null) {
164321
164370
  const storage2 = env.get(LockCredentialStorage);
164322
164371
  await storage2.deleteCredential(entityId);
164372
+ passthrough?.callAction(
164373
+ buildUsercodeClearAction(passthrough.service, passthrough.slot)
164374
+ );
164375
+ }
164376
+ }
164377
+ async function applyClearUser(env, entityId, request, passthrough) {
164378
+ const slot = normalizeSupportedIndex(request.userIndex);
164379
+ if (slot === null && request.userIndex !== 65534) {
164380
+ return;
164381
+ }
164382
+ const storage2 = env.get(LockCredentialStorage);
164383
+ const hadCredential = storage2.hasCredential(entityId);
164384
+ await storage2.deleteCredential(entityId);
164385
+ if (hadCredential) {
164386
+ passthrough?.callAction(
164387
+ buildUsercodeClearAction(passthrough.service, passthrough.slot)
164388
+ );
164323
164389
  }
164324
164390
  }
164325
164391
  var LockServerBase = class extends DoorLockServer {
@@ -164495,12 +164561,13 @@ var LockServerWithPinBase = class extends PinCredentialBase {
164495
164561
  );
164496
164562
  }
164497
164563
  async clearUser(request) {
164498
- const slot = normalizeSupportedIndex(request.userIndex);
164499
- if (slot !== null || request.userIndex === 65534) {
164500
- const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
164501
- const storage2 = this.env.get(LockCredentialStorage);
164502
- await storage2.deleteCredential(homeAssistant.entityId);
164503
- }
164564
+ const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
164565
+ await applyClearUser(
164566
+ this.env,
164567
+ homeAssistant.entityId,
164568
+ request,
164569
+ usercodePassthroughFrom(homeAssistant)
164570
+ );
164504
164571
  }
164505
164572
  async setCredential(request) {
164506
164573
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
@@ -164508,7 +164575,8 @@ var LockServerWithPinBase = class extends PinCredentialBase {
164508
164575
  this.env,
164509
164576
  homeAssistant.entityId,
164510
164577
  request,
164511
- this.context.fabric
164578
+ this.context.fabric,
164579
+ usercodePassthroughFrom(homeAssistant)
164512
164580
  );
164513
164581
  }
164514
164582
  getCredentialStatus(request) {
@@ -164521,7 +164589,12 @@ var LockServerWithPinBase = class extends PinCredentialBase {
164521
164589
  }
164522
164590
  async clearCredential(request) {
164523
164591
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
164524
- await applyClearCredential(this.env, homeAssistant.entityId, request);
164592
+ await applyClearCredential(
164593
+ this.env,
164594
+ homeAssistant.entityId,
164595
+ request,
164596
+ usercodePassthroughFrom(homeAssistant)
164597
+ );
164525
164598
  }
164526
164599
  };
164527
164600
  ((LockServerWithPinBase2) => {
@@ -164691,12 +164764,13 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
164691
164764
  );
164692
164765
  }
164693
164766
  async clearUser(request) {
164694
- const slot = normalizeSupportedIndex(request.userIndex);
164695
- if (slot !== null || request.userIndex === 65534) {
164696
- const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
164697
- const storage2 = this.env.get(LockCredentialStorage);
164698
- await storage2.deleteCredential(homeAssistant.entityId);
164699
- }
164767
+ const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
164768
+ await applyClearUser(
164769
+ this.env,
164770
+ homeAssistant.entityId,
164771
+ request,
164772
+ usercodePassthroughFrom(homeAssistant)
164773
+ );
164700
164774
  }
164701
164775
  async setCredential(request) {
164702
164776
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
@@ -164704,7 +164778,8 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
164704
164778
  this.env,
164705
164779
  homeAssistant.entityId,
164706
164780
  request,
164707
- this.context.fabric
164781
+ this.context.fabric,
164782
+ usercodePassthroughFrom(homeAssistant)
164708
164783
  );
164709
164784
  }
164710
164785
  getCredentialStatus(request) {
@@ -164717,7 +164792,12 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
164717
164792
  }
164718
164793
  async clearCredential(request) {
164719
164794
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
164720
- await applyClearCredential(this.env, homeAssistant.entityId, request);
164795
+ await applyClearCredential(
164796
+ this.env,
164797
+ homeAssistant.entityId,
164798
+ request,
164799
+ usercodePassthroughFrom(homeAssistant)
164800
+ );
164721
164801
  }
164722
164802
  };
164723
164803
  ((LockServerWithPinAndUnboltBase2) => {
@@ -170440,7 +170520,11 @@ init_esm();
170440
170520
  init_esm3();
170441
170521
 
170442
170522
  // src/plugins/builtin/camera/av-stream-server.ts
170443
- var Base4 = CameraAvStreamManagementServer.with("Video", "Audio", "Snapshot");
170523
+ var Base4 = CameraAvStreamManagementServer.with(
170524
+ "Video",
170525
+ "Snapshot",
170526
+ "ImageControl"
170527
+ );
170444
170528
  var CameraAvStreamServer = class extends Base4 {
170445
170529
  setStreamPriorities(request) {
170446
170530
  this.state.streamUsagePriorities = request.streamPriorities;
@@ -170472,28 +170556,6 @@ var CameraAvStreamServer = class extends Base4 {
170472
170556
  (s) => s.videoStreamId !== request.videoStreamId
170473
170557
  );
170474
170558
  }
170475
- audioStreamAllocate(request) {
170476
- const audioStreamId = this.state.nextAudioStreamId++;
170477
- this.state.allocatedAudioStreams = [
170478
- ...this.state.allocatedAudioStreams,
170479
- {
170480
- audioStreamId,
170481
- streamUsage: request.streamUsage,
170482
- audioCodec: request.audioCodec,
170483
- channelCount: request.channelCount,
170484
- sampleRate: request.sampleRate,
170485
- bitRate: request.bitRate,
170486
- bitDepth: request.bitDepth,
170487
- referenceCount: 1
170488
- }
170489
- ];
170490
- return { audioStreamId };
170491
- }
170492
- audioStreamDeallocate(request) {
170493
- this.state.allocatedAudioStreams = this.state.allocatedAudioStreams.filter(
170494
- (s) => s.audioStreamId !== request.audioStreamId
170495
- );
170496
- }
170497
170559
  snapshotStreamAllocate(request) {
170498
170560
  const snapshotStreamId = this.state.nextSnapshotStreamId++;
170499
170561
  this.state.allocatedSnapshotStreams = [
@@ -170531,7 +170593,6 @@ var CameraAvStreamServer = class extends Base4 {
170531
170593
  bridge;
170532
170594
  entityId;
170533
170595
  nextVideoStreamId = 1;
170534
- nextAudioStreamId = 1;
170535
170596
  nextSnapshotStreamId = 1;
170536
170597
  }
170537
170598
  CameraAvStreamServer2.State = State;
@@ -170611,7 +170672,12 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
170611
170672
  })(CameraWebRtcProviderServer || (CameraWebRtcProviderServer = {}));
170612
170673
 
170613
170674
  // src/plugins/builtin/camera/camera-endpoint.ts
170614
- function createCameraEndpointType(bridge, entityId) {
170675
+ var defaultSensorParams = {
170676
+ sensorWidth: 1920,
170677
+ sensorHeight: 1080,
170678
+ maxFps: 30
170679
+ };
170680
+ function createCameraEndpointType(bridge, entityId, sensor = defaultSensorParams) {
170615
170681
  return CameraDevice.with(
170616
170682
  CameraAvStreamServer,
170617
170683
  CameraWebRtcProviderServer
@@ -170628,14 +170694,54 @@ function createCameraEndpointType(bridge, entityId) {
170628
170694
  supportedStreamUsages: [StreamUsage.LiveView],
170629
170695
  streamUsagePriorities: [StreamUsage.LiveView],
170630
170696
  allocatedVideoStreams: [],
170631
- allocatedAudioStreams: [],
170632
170697
  allocatedSnapshotStreams: [],
170633
170698
  maxConcurrentEncoders: 1,
170634
170699
  maxEncodedPixelRate: 3840 * 2160 * 30,
170635
- maxNetworkBandwidth: 2e4,
170700
+ maxNetworkBandwidth: 2e7,
170701
+ // 20 Mbps, attribute is bits per second
170636
170702
  currentFrameRate: 0,
170703
+ videoSensorParams: {
170704
+ sensorWidth: sensor.sensorWidth,
170705
+ sensorHeight: sensor.sensorHeight,
170706
+ maxFps: sensor.maxFps
170707
+ },
170708
+ viewport: {
170709
+ x1: 0,
170710
+ y1: 0,
170711
+ x2: sensor.sensorWidth,
170712
+ y2: sensor.sensorHeight
170713
+ },
170714
+ minViewportResolution: { width: 64, height: 64 },
170715
+ rateDistortionTradeOffPoints: [
170716
+ {
170717
+ codec: CameraAvStreamManagement3.VideoCodec.H264,
170718
+ resolution: {
170719
+ width: sensor.sensorWidth,
170720
+ height: sensor.sensorHeight
170721
+ },
170722
+ minBitRate: 1e4
170723
+ }
170724
+ ],
170725
+ maxContentBufferSize: 1048576,
170726
+ // one snapshot jpeg in flight
170727
+ // ImageControl attributes: matter.js 0.17.5 conformance forces the
170728
+ // feature. Controllers can write these but the proxied HA media path
170729
+ // never applies a transform.
170730
+ imageRotation: 0,
170731
+ imageFlipHorizontal: false,
170732
+ imageFlipVertical: false,
170733
+ snapshotCapabilities: [
170734
+ {
170735
+ resolution: {
170736
+ width: sensor.sensorWidth,
170737
+ height: sensor.sensorHeight
170738
+ },
170739
+ maxFrameRate: 1,
170740
+ imageCodec: CameraAvStreamManagement3.ImageCodec.Jpeg,
170741
+ requiresEncodedPixels: false
170742
+ }
170743
+ ],
170637
170744
  nextVideoStreamId: 1,
170638
- nextAudioStreamId: 1,
170639
170745
  nextSnapshotStreamId: 1
170640
170746
  }
170641
170747
  });
@@ -170848,6 +170954,27 @@ var CameraPlugin = class {
170848
170954
  title: "Camera entity ids (comma-separated)",
170849
170955
  description: "e.g. camera.front,camera.garage",
170850
170956
  required: true
170957
+ },
170958
+ sensorWidth: {
170959
+ type: "number",
170960
+ title: "Sensor width (px)",
170961
+ description: "Video sensor width reported to controllers.",
170962
+ default: defaultSensorParams.sensorWidth,
170963
+ required: false
170964
+ },
170965
+ sensorHeight: {
170966
+ type: "number",
170967
+ title: "Sensor height (px)",
170968
+ description: "Video sensor height reported to controllers.",
170969
+ default: defaultSensorParams.sensorHeight,
170970
+ required: false
170971
+ },
170972
+ maxFps: {
170973
+ type: "number",
170974
+ title: "Max frame rate (fps)",
170975
+ description: "Maximum frame rate the sensor supports.",
170976
+ default: defaultSensorParams.maxFps,
170977
+ required: false
170851
170978
  }
170852
170979
  }
170853
170980
  };
@@ -170869,19 +170996,37 @@ var CameraPlugin = class {
170869
170996
  this.log.info("no camera entity ids configured");
170870
170997
  return;
170871
170998
  }
170999
+ const sensor = this.sensorParams();
170872
171000
  this.bridge = new WebRtcBridge({ haUrl, haToken });
170873
171001
  for (const entityId of entityIds) {
170874
171002
  const id = entityId.replace(/\./g, "_");
170875
171003
  await context.registerDevice({
170876
171004
  id,
170877
171005
  name: entityId,
170878
- endpointType: createCameraEndpointType(this.bridge, entityId),
171006
+ endpointType: createCameraEndpointType(this.bridge, entityId, sensor),
170879
171007
  clusters: []
170880
171008
  });
170881
171009
  this.deviceIds.push(id);
170882
171010
  }
170883
171011
  this.log.info(`Exposed ${this.deviceIds.length} camera(s)`);
170884
171012
  }
171013
+ // Clamp the configured sensor to values the cluster accepts; a bad or missing
171014
+ // entry falls back to the default for that field.
171015
+ sensorParams() {
171016
+ const dim = (n, fallback) => typeof n === "number" && Number.isFinite(n) ? Math.min(65535, Math.max(64, Math.floor(n))) : fallback;
171017
+ const fps = (n, fallback) => typeof n === "number" && Number.isFinite(n) ? Math.min(65535, Math.max(1, Math.floor(n))) : fallback;
171018
+ return {
171019
+ sensorWidth: dim(
171020
+ this.config.sensorWidth,
171021
+ defaultSensorParams.sensorWidth
171022
+ ),
171023
+ sensorHeight: dim(
171024
+ this.config.sensorHeight,
171025
+ defaultSensorParams.sensorHeight
171026
+ ),
171027
+ maxFps: fps(this.config.maxFps, defaultSensorParams.maxFps)
171028
+ };
171029
+ }
170885
171030
  async teardown() {
170886
171031
  for (const id of this.deviceIds) {
170887
171032
  await this.context?.unregisterDevice(id).catch(() => {