@camstack/addon-provider-unraid 0.1.3 → 0.1.5

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
@@ -4642,7 +4642,7 @@ function preprocess(fn, schema) {
4642
4642
  });
4643
4643
  }
4644
4644
  //#endregion
4645
- //#region ../types/dist/sleep-BiDFW0E7.mjs
4645
+ //#region ../types/dist/sleep-CZDdRBua.mjs
4646
4646
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4647
4647
  EventCategory["SystemBoot"] = "system.boot";
4648
4648
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -7253,7 +7253,16 @@ var DecoderStatsSchema = object({
7253
7253
  inputFps: number(),
7254
7254
  outputFps: number(),
7255
7255
  avgDecodeTimeMs: number(),
7256
- droppedFrames: number()
7256
+ droppedFrames: number(),
7257
+ /**
7258
+ * Pull-mode adaptive-fps telemetry (optional — only pull sessions run the
7259
+ * lag-driven controller; push sessions omit these). `lagMs` is the EWMA of
7260
+ * the decoder's real-time drift (rising = falling behind live); `adaptiveFps`
7261
+ * is the current lag-throttled emit rate (≤ `effectiveFps` ceiling).
7262
+ */
7263
+ lagMs: number().optional(),
7264
+ effectiveFps: number().optional(),
7265
+ adaptiveFps: number().optional()
7257
7266
  });
7258
7267
  var DecoderSessionConfigSchema = object({
7259
7268
  codec: string(),
@@ -7294,7 +7303,15 @@ var DecoderSessionConfigSchema = object({
7294
7303
  * other — `pullFrames` returns nothing for an `'shm'` session and
7295
7304
  * `pullHandles` returns nothing for a `'callback'` session.
7296
7305
  */
7297
- frameSink: _enum(["callback", "shm"]).default("callback")
7306
+ frameSink: _enum(["callback", "shm"]).default("callback"),
7307
+ /**
7308
+ * Per-camera decoder DEBUG facility. When `true`, a pull-mode session emits
7309
+ * a throttled (~1Hz) structured `decoder debug` line (effective/adaptive fps,
7310
+ * real-time lag, dropped-frame delta, avg decode time, hwaccel). Mirrors the
7311
+ * stream-broker's `streamingDebug` gate — off by default so production logs
7312
+ * stay quiet and the emit path pays zero per-frame cost when disabled.
7313
+ */
7314
+ debug: boolean().optional()
7298
7315
  });
7299
7316
  var EncodeProfileSchema = object({
7300
7317
  video: object({
@@ -10319,6 +10336,100 @@ var coverCapability = {
10319
10336
  runtimeState: CoverStatusSchema
10320
10337
  };
10321
10338
  /**
10339
+ * Vendor-neutral day/night (IR-cut) control — the per-camera config cap
10340
+ * shared by reolink / hikvision / amcrest. Models the common firmware
10341
+ * surface: the IR-cut switching MODE plus the two knobs that gate it
10342
+ * (photocell `sensitivity` + `switchDelaySec`). Each vendor maps these
10343
+ * onto its own ISAPI / Baichuan / Dahua-CGI fields; the cap standardises
10344
+ * the shape so ONE derived-form renders every camera.
10345
+ *
10346
+ * Follows the D14 `deviceConfig` archetype (see `stream-params.cap.ts`):
10347
+ * `getOptions` advertises per-camera availability, `getStatus` (auto-
10348
+ * injected from `status`) reports the live values, and a single
10349
+ * `setSettings` mutation applies a partial change. No hand-written
10350
+ * settings-contribution methods — the framework derives the UI + save
10351
+ * routing from this surface.
10352
+ */
10353
+ /** IR-cut switching mode. `schedule` = time-of-day table configured on the camera. */
10354
+ var DayNightModeSchema = _enum([
10355
+ "auto",
10356
+ "day",
10357
+ "night",
10358
+ "schedule"
10359
+ ]);
10360
+ /** Normalized numeric range descriptor — `{ min, max, step }` per the
10361
+ * getOptions availability convention. Normalized values are 0–100. */
10362
+ var NormalizedRangeSchema$1 = object({
10363
+ min: number(),
10364
+ max: number(),
10365
+ step: number()
10366
+ });
10367
+ /**
10368
+ * Current day/night state. Optional fields are absent when the camera
10369
+ * does not expose that knob (a photocell-less model reports no
10370
+ * `sensitivity`). `lastFetchedAt` feeds the runtime-state bridge.
10371
+ */
10372
+ var DayNightStatusSchema = object({
10373
+ mode: DayNightModeSchema,
10374
+ /** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
10375
+ sensitivity: number().optional(),
10376
+ /** Delay before the IR-cut filter flips, in seconds. */
10377
+ switchDelaySec: number().optional(),
10378
+ lastFetchedAt: number()
10379
+ });
10380
+ /**
10381
+ * Per-camera availability descriptor — drives which controls the admin UI
10382
+ * renders. Booleans as `supportsX`; numeric ranges as `{ min, max, step }`
10383
+ * (normalized 0–100); the mode choice-set as an array. A provider returns
10384
+ * honest, camera-probed values — never hardcoded.
10385
+ */
10386
+ var DayNightOptionsSchema = object({
10387
+ /** Modes this camera accepts. Empty → the camera has no configurable day/night mode. */
10388
+ modes: array(DayNightModeSchema),
10389
+ supportsSensitivity: boolean(),
10390
+ /** Present when `supportsSensitivity` — the normalized 0–100 range. */
10391
+ sensitivity: NormalizedRangeSchema$1.optional(),
10392
+ supportsSwitchDelay: boolean(),
10393
+ /** Present when `supportsSwitchDelay` — the allowed delay range in seconds. */
10394
+ switchDelaySec: NormalizedRangeSchema$1.optional()
10395
+ });
10396
+ /**
10397
+ * Partial change to the day/night config — every field optional. A
10398
+ * provider ignores fields it does not support.
10399
+ */
10400
+ var DayNightSettingsPatchSchema = object({
10401
+ mode: DayNightModeSchema.optional(),
10402
+ sensitivity: number().optional(),
10403
+ switchDelaySec: number().optional()
10404
+ });
10405
+ var dayNightCapability = {
10406
+ name: "day-night",
10407
+ scope: "device",
10408
+ deviceNative: true,
10409
+ mode: "singleton",
10410
+ deviceTypes: [DeviceType.Camera],
10411
+ deviceConfig: { ui: {
10412
+ kind: "derived-form",
10413
+ builderId: "day-night",
10414
+ tab: "image"
10415
+ } },
10416
+ methods: {
10417
+ getOptions: method(object({ deviceId: number() }), DayNightOptionsSchema),
10418
+ setSettings: method(object({
10419
+ deviceId: number(),
10420
+ settings: DayNightSettingsPatchSchema
10421
+ }), _void(), {
10422
+ kind: "mutation",
10423
+ auth: "admin"
10424
+ })
10425
+ },
10426
+ status: {
10427
+ schema: DayNightStatusSchema,
10428
+ kind: "poll"
10429
+ },
10430
+ runtimeState: DayNightStatusSchema
10431
+ };
10432
+ /**
10322
10433
  * Identity envelope for a device's upstream-system metadata.
10323
10434
  *
10324
10435
  * Two jobs:
@@ -10977,6 +11088,155 @@ var imageCapability = {
10977
11088
  runtimeState: ImageStatusSchema
10978
11089
  };
10979
11090
  /**
11091
+ * Vendor-neutral image / picture-adjustment cap — the per-camera config
11092
+ * cap shared by reolink / hikvision / amcrest. Models the common ISP
11093
+ * surface: the four picture sliders (brightness / contrast / saturation /
11094
+ * sharpness), orientation (mirror / flip / rotate), white-balance,
11095
+ * exposure and backlight-compensation modes.
11096
+ *
11097
+ * NORMALIZATION: every slider is a normalized int 0–100. Vendors expose
11098
+ * these natively as 0–100 or 0–255 (or other ranges); each provider maps
11099
+ * its native range to/from this normalized 0–100 space so the cap surface
11100
+ * (and the derived form) is identical across cameras. `warmth` (manual
11101
+ * white-balance) is likewise normalized 0–100.
11102
+ *
11103
+ * Follows the D14 `deviceConfig` archetype (see `stream-params.cap.ts`):
11104
+ * `getOptions` advertises per-camera availability, `getStatus` (auto-
11105
+ * injected from `status`) reports the live values, and a single
11106
+ * `setSettings` mutation applies a partial change. No hand-written
11107
+ * settings-contribution methods — the framework derives the UI + save
11108
+ * routing from this surface.
11109
+ */
11110
+ /** Sensor/image rotation, degrees clockwise. */
11111
+ var ImageRotateSchema = _enum([
11112
+ "0",
11113
+ "90",
11114
+ "180",
11115
+ "270"
11116
+ ]);
11117
+ /** White-balance mode. `manual` unlocks the normalized `warmth` knob. */
11118
+ var WhiteBalanceModeSchema = _enum(["auto", "manual"]);
11119
+ /** Exposure mode. */
11120
+ var ExposureModeSchema = _enum(["auto", "manual"]);
11121
+ /**
11122
+ * Backlight-compensation mode:
11123
+ * - `off` — disabled
11124
+ * - `blc` — backlight compensation
11125
+ * - `wdr` — wide dynamic range
11126
+ * - `hlc` — highlight compensation
11127
+ */
11128
+ var BacklightModeSchema = _enum([
11129
+ "off",
11130
+ "blc",
11131
+ "wdr",
11132
+ "hlc"
11133
+ ]);
11134
+ /** Normalized numeric range descriptor — `{ min, max, step }` per the
11135
+ * getOptions availability convention. Slider values are normalized 0–100. */
11136
+ var NormalizedRangeSchema = object({
11137
+ min: number(),
11138
+ max: number(),
11139
+ step: number()
11140
+ });
11141
+ /**
11142
+ * Current image-adjustment state. Every field optional — absent when the
11143
+ * camera does not expose that control. Slider values are NORMALIZED 0–100.
11144
+ * `lastFetchedAt` feeds the runtime-state bridge.
11145
+ */
11146
+ var ImageSettingsStatusSchema = object({
11147
+ /** Normalized 0–100. */
11148
+ brightness: number().optional(),
11149
+ /** Normalized 0–100. */
11150
+ contrast: number().optional(),
11151
+ /** Normalized 0–100. */
11152
+ saturation: number().optional(),
11153
+ /** Normalized 0–100. */
11154
+ sharpness: number().optional(),
11155
+ mirror: boolean().optional(),
11156
+ flip: boolean().optional(),
11157
+ rotate: ImageRotateSchema.optional(),
11158
+ whiteBalance: WhiteBalanceModeSchema.optional(),
11159
+ /** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
11160
+ warmth: number().optional(),
11161
+ exposureMode: ExposureModeSchema.optional(),
11162
+ backlightMode: BacklightModeSchema.optional(),
11163
+ lastFetchedAt: number()
11164
+ });
11165
+ /**
11166
+ * Per-camera availability descriptor — drives which controls the admin UI
11167
+ * renders. Booleans as `supportsX`; numeric ranges as `{ min, max, step }`
11168
+ * (the normalized 0–100 range); enums as arrays of supported values (empty
11169
+ * array → control hidden). A provider returns honest, camera-probed values
11170
+ * — never hardcoded.
11171
+ */
11172
+ var ImageSettingsOptionsSchema = object({
11173
+ supportsBrightness: boolean(),
11174
+ brightness: NormalizedRangeSchema.optional(),
11175
+ supportsContrast: boolean(),
11176
+ contrast: NormalizedRangeSchema.optional(),
11177
+ supportsSaturation: boolean(),
11178
+ saturation: NormalizedRangeSchema.optional(),
11179
+ supportsSharpness: boolean(),
11180
+ sharpness: NormalizedRangeSchema.optional(),
11181
+ supportsMirror: boolean(),
11182
+ supportsFlip: boolean(),
11183
+ /** Supported rotation values. Empty → rotation not configurable. */
11184
+ rotateOptions: array(ImageRotateSchema),
11185
+ /** Supported white-balance modes. Empty → white-balance not configurable. */
11186
+ whiteBalanceModes: array(WhiteBalanceModeSchema),
11187
+ supportsWarmth: boolean(),
11188
+ /** Present when `supportsWarmth` — the normalized 0–100 range. */
11189
+ warmth: NormalizedRangeSchema.optional(),
11190
+ /** Supported exposure modes. Empty → exposure not configurable. */
11191
+ exposureModes: array(ExposureModeSchema),
11192
+ /** Supported backlight modes. Empty → backlight-compensation not configurable. */
11193
+ backlightModes: array(BacklightModeSchema)
11194
+ });
11195
+ /**
11196
+ * Partial change to the image config — every field optional. Slider values
11197
+ * are normalized 0–100. A provider ignores fields it does not support.
11198
+ */
11199
+ var ImageSettingsPatchSchema = object({
11200
+ brightness: number().optional(),
11201
+ contrast: number().optional(),
11202
+ saturation: number().optional(),
11203
+ sharpness: number().optional(),
11204
+ mirror: boolean().optional(),
11205
+ flip: boolean().optional(),
11206
+ rotate: ImageRotateSchema.optional(),
11207
+ whiteBalance: WhiteBalanceModeSchema.optional(),
11208
+ warmth: number().optional(),
11209
+ exposureMode: ExposureModeSchema.optional(),
11210
+ backlightMode: BacklightModeSchema.optional()
11211
+ });
11212
+ var imageSettingsCapability = {
11213
+ name: "image-settings",
11214
+ scope: "device",
11215
+ deviceNative: true,
11216
+ mode: "singleton",
11217
+ deviceTypes: [DeviceType.Camera],
11218
+ deviceConfig: { ui: {
11219
+ kind: "derived-form",
11220
+ builderId: "image-settings",
11221
+ tab: "image"
11222
+ } },
11223
+ methods: {
11224
+ getOptions: method(object({ deviceId: number() }), ImageSettingsOptionsSchema),
11225
+ setSettings: method(object({
11226
+ deviceId: number(),
11227
+ settings: ImageSettingsPatchSchema
11228
+ }), _void(), {
11229
+ kind: "mutation",
11230
+ auth: "admin"
11231
+ })
11232
+ },
11233
+ status: {
11234
+ schema: ImageSettingsStatusSchema,
11235
+ kind: "poll"
11236
+ },
11237
+ runtimeState: ImageSettingsStatusSchema
11238
+ };
11239
+ /**
10980
11240
  * Robotic lawn-mower cap. Models HA `lawn_mower.*` entities — anything
10981
11241
  * with a mowing lifecycle plus a dock action.
10982
11242
  *
@@ -11975,6 +12235,16 @@ var RunnerCameraConfigSchema = object({
11975
12235
  * this gate is bypassed.
11976
12236
  */
11977
12237
  onboardMotionDrivesAnalyzer: boolean().default(true),
12238
+ /**
12239
+ * Master toggle for the occupancy re-check. When `false` (DEFAULT) the runner
12240
+ * never arms the periodic recheck timer, regardless of `occupancyRecheckSec` —
12241
+ * this is off by default because the recheck re-subscribes a detection session
12242
+ * every N seconds while `watching`, a major source of pull-decoder re-dial
12243
+ * churn (each cycle creates+tears a session → RTSP re-dial → latency). The
12244
+ * `occupancyRecheckSec` / `occupancyRecheckFrames` sliders only take effect
12245
+ * (and only render) when this is enabled.
12246
+ */
12247
+ occupancyRecheckEnabled: boolean().default(false),
11978
12248
  occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
11979
12249
  occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
11980
12250
  /**
@@ -13980,6 +14250,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
13980
14250
  contact: contactCapability,
13981
14251
  control: controlCapability,
13982
14252
  cover: coverCapability,
14253
+ dayNight: dayNightCapability,
13983
14254
  deviceDiscovery: deviceDiscoveryCapability,
13984
14255
  deviceStatus: deviceStatusCapability,
13985
14256
  doorbell: doorbellCapability,
@@ -13992,6 +14263,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
13992
14263
  humidifier: humidifierCapability,
13993
14264
  humiditySensor: humiditySensorCapability,
13994
14265
  image: imageCapability,
14266
+ imageSettings: imageSettingsCapability,
13995
14267
  lawnMowerControl: lawnMowerControlCapability,
13996
14268
  lockControl: lockControlCapability,
13997
14269
  mediaPlayer: mediaPlayerCapability,
@@ -15906,7 +16178,9 @@ method(object({ codec: string() }), boolean()), method(_void(), object({
15906
16178
  id: string(),
15907
16179
  name: string(),
15908
16180
  isPullMode: boolean().optional(),
15909
- priority: number().optional()
16181
+ priority: number().optional(),
16182
+ hwaccel: string().optional(),
16183
+ probedBestHwaccel: string().optional()
15910
16184
  })), method(DecoderSessionConfigSchema, object({
15911
16185
  sessionId: string(),
15912
16186
  nodeId: string()
@@ -21915,6 +22189,18 @@ Object.freeze({
21915
22189
  addonId: null,
21916
22190
  access: "view"
21917
22191
  },
22192
+ "dayNight.getOptions": {
22193
+ capName: "day-night",
22194
+ capScope: "device",
22195
+ addonId: null,
22196
+ access: "view"
22197
+ },
22198
+ "dayNight.setSettings": {
22199
+ capName: "day-night",
22200
+ capScope: "device",
22201
+ addonId: null,
22202
+ access: "create"
22203
+ },
21918
22204
  "decoder.createSession": {
21919
22205
  capName: "decoder",
21920
22206
  capScope: "system",
@@ -22845,6 +23131,18 @@ Object.freeze({
22845
23131
  addonId: null,
22846
23132
  access: "create"
22847
23133
  },
23134
+ "imageSettings.getOptions": {
23135
+ capName: "image-settings",
23136
+ capScope: "device",
23137
+ addonId: null,
23138
+ access: "view"
23139
+ },
23140
+ "imageSettings.setSettings": {
23141
+ capName: "image-settings",
23142
+ capScope: "device",
23143
+ addonId: null,
23144
+ access: "create"
23145
+ },
22848
23146
  "integrations.create": {
22849
23147
  capName: "integrations",
22850
23148
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -4641,7 +4641,7 @@ function preprocess(fn, schema) {
4641
4641
  });
4642
4642
  }
4643
4643
  //#endregion
4644
- //#region ../types/dist/sleep-BiDFW0E7.mjs
4644
+ //#region ../types/dist/sleep-CZDdRBua.mjs
4645
4645
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4646
4646
  EventCategory["SystemBoot"] = "system.boot";
4647
4647
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -7252,7 +7252,16 @@ var DecoderStatsSchema = object({
7252
7252
  inputFps: number(),
7253
7253
  outputFps: number(),
7254
7254
  avgDecodeTimeMs: number(),
7255
- droppedFrames: number()
7255
+ droppedFrames: number(),
7256
+ /**
7257
+ * Pull-mode adaptive-fps telemetry (optional — only pull sessions run the
7258
+ * lag-driven controller; push sessions omit these). `lagMs` is the EWMA of
7259
+ * the decoder's real-time drift (rising = falling behind live); `adaptiveFps`
7260
+ * is the current lag-throttled emit rate (≤ `effectiveFps` ceiling).
7261
+ */
7262
+ lagMs: number().optional(),
7263
+ effectiveFps: number().optional(),
7264
+ adaptiveFps: number().optional()
7256
7265
  });
7257
7266
  var DecoderSessionConfigSchema = object({
7258
7267
  codec: string(),
@@ -7293,7 +7302,15 @@ var DecoderSessionConfigSchema = object({
7293
7302
  * other — `pullFrames` returns nothing for an `'shm'` session and
7294
7303
  * `pullHandles` returns nothing for a `'callback'` session.
7295
7304
  */
7296
- frameSink: _enum(["callback", "shm"]).default("callback")
7305
+ frameSink: _enum(["callback", "shm"]).default("callback"),
7306
+ /**
7307
+ * Per-camera decoder DEBUG facility. When `true`, a pull-mode session emits
7308
+ * a throttled (~1Hz) structured `decoder debug` line (effective/adaptive fps,
7309
+ * real-time lag, dropped-frame delta, avg decode time, hwaccel). Mirrors the
7310
+ * stream-broker's `streamingDebug` gate — off by default so production logs
7311
+ * stay quiet and the emit path pays zero per-frame cost when disabled.
7312
+ */
7313
+ debug: boolean().optional()
7297
7314
  });
7298
7315
  var EncodeProfileSchema = object({
7299
7316
  video: object({
@@ -10318,6 +10335,100 @@ var coverCapability = {
10318
10335
  runtimeState: CoverStatusSchema
10319
10336
  };
10320
10337
  /**
10338
+ * Vendor-neutral day/night (IR-cut) control — the per-camera config cap
10339
+ * shared by reolink / hikvision / amcrest. Models the common firmware
10340
+ * surface: the IR-cut switching MODE plus the two knobs that gate it
10341
+ * (photocell `sensitivity` + `switchDelaySec`). Each vendor maps these
10342
+ * onto its own ISAPI / Baichuan / Dahua-CGI fields; the cap standardises
10343
+ * the shape so ONE derived-form renders every camera.
10344
+ *
10345
+ * Follows the D14 `deviceConfig` archetype (see `stream-params.cap.ts`):
10346
+ * `getOptions` advertises per-camera availability, `getStatus` (auto-
10347
+ * injected from `status`) reports the live values, and a single
10348
+ * `setSettings` mutation applies a partial change. No hand-written
10349
+ * settings-contribution methods — the framework derives the UI + save
10350
+ * routing from this surface.
10351
+ */
10352
+ /** IR-cut switching mode. `schedule` = time-of-day table configured on the camera. */
10353
+ var DayNightModeSchema = _enum([
10354
+ "auto",
10355
+ "day",
10356
+ "night",
10357
+ "schedule"
10358
+ ]);
10359
+ /** Normalized numeric range descriptor — `{ min, max, step }` per the
10360
+ * getOptions availability convention. Normalized values are 0–100. */
10361
+ var NormalizedRangeSchema$1 = object({
10362
+ min: number(),
10363
+ max: number(),
10364
+ step: number()
10365
+ });
10366
+ /**
10367
+ * Current day/night state. Optional fields are absent when the camera
10368
+ * does not expose that knob (a photocell-less model reports no
10369
+ * `sensitivity`). `lastFetchedAt` feeds the runtime-state bridge.
10370
+ */
10371
+ var DayNightStatusSchema = object({
10372
+ mode: DayNightModeSchema,
10373
+ /** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
10374
+ sensitivity: number().optional(),
10375
+ /** Delay before the IR-cut filter flips, in seconds. */
10376
+ switchDelaySec: number().optional(),
10377
+ lastFetchedAt: number()
10378
+ });
10379
+ /**
10380
+ * Per-camera availability descriptor — drives which controls the admin UI
10381
+ * renders. Booleans as `supportsX`; numeric ranges as `{ min, max, step }`
10382
+ * (normalized 0–100); the mode choice-set as an array. A provider returns
10383
+ * honest, camera-probed values — never hardcoded.
10384
+ */
10385
+ var DayNightOptionsSchema = object({
10386
+ /** Modes this camera accepts. Empty → the camera has no configurable day/night mode. */
10387
+ modes: array(DayNightModeSchema),
10388
+ supportsSensitivity: boolean(),
10389
+ /** Present when `supportsSensitivity` — the normalized 0–100 range. */
10390
+ sensitivity: NormalizedRangeSchema$1.optional(),
10391
+ supportsSwitchDelay: boolean(),
10392
+ /** Present when `supportsSwitchDelay` — the allowed delay range in seconds. */
10393
+ switchDelaySec: NormalizedRangeSchema$1.optional()
10394
+ });
10395
+ /**
10396
+ * Partial change to the day/night config — every field optional. A
10397
+ * provider ignores fields it does not support.
10398
+ */
10399
+ var DayNightSettingsPatchSchema = object({
10400
+ mode: DayNightModeSchema.optional(),
10401
+ sensitivity: number().optional(),
10402
+ switchDelaySec: number().optional()
10403
+ });
10404
+ var dayNightCapability = {
10405
+ name: "day-night",
10406
+ scope: "device",
10407
+ deviceNative: true,
10408
+ mode: "singleton",
10409
+ deviceTypes: [DeviceType.Camera],
10410
+ deviceConfig: { ui: {
10411
+ kind: "derived-form",
10412
+ builderId: "day-night",
10413
+ tab: "image"
10414
+ } },
10415
+ methods: {
10416
+ getOptions: method(object({ deviceId: number() }), DayNightOptionsSchema),
10417
+ setSettings: method(object({
10418
+ deviceId: number(),
10419
+ settings: DayNightSettingsPatchSchema
10420
+ }), _void(), {
10421
+ kind: "mutation",
10422
+ auth: "admin"
10423
+ })
10424
+ },
10425
+ status: {
10426
+ schema: DayNightStatusSchema,
10427
+ kind: "poll"
10428
+ },
10429
+ runtimeState: DayNightStatusSchema
10430
+ };
10431
+ /**
10321
10432
  * Identity envelope for a device's upstream-system metadata.
10322
10433
  *
10323
10434
  * Two jobs:
@@ -10976,6 +11087,155 @@ var imageCapability = {
10976
11087
  runtimeState: ImageStatusSchema
10977
11088
  };
10978
11089
  /**
11090
+ * Vendor-neutral image / picture-adjustment cap — the per-camera config
11091
+ * cap shared by reolink / hikvision / amcrest. Models the common ISP
11092
+ * surface: the four picture sliders (brightness / contrast / saturation /
11093
+ * sharpness), orientation (mirror / flip / rotate), white-balance,
11094
+ * exposure and backlight-compensation modes.
11095
+ *
11096
+ * NORMALIZATION: every slider is a normalized int 0–100. Vendors expose
11097
+ * these natively as 0–100 or 0–255 (or other ranges); each provider maps
11098
+ * its native range to/from this normalized 0–100 space so the cap surface
11099
+ * (and the derived form) is identical across cameras. `warmth` (manual
11100
+ * white-balance) is likewise normalized 0–100.
11101
+ *
11102
+ * Follows the D14 `deviceConfig` archetype (see `stream-params.cap.ts`):
11103
+ * `getOptions` advertises per-camera availability, `getStatus` (auto-
11104
+ * injected from `status`) reports the live values, and a single
11105
+ * `setSettings` mutation applies a partial change. No hand-written
11106
+ * settings-contribution methods — the framework derives the UI + save
11107
+ * routing from this surface.
11108
+ */
11109
+ /** Sensor/image rotation, degrees clockwise. */
11110
+ var ImageRotateSchema = _enum([
11111
+ "0",
11112
+ "90",
11113
+ "180",
11114
+ "270"
11115
+ ]);
11116
+ /** White-balance mode. `manual` unlocks the normalized `warmth` knob. */
11117
+ var WhiteBalanceModeSchema = _enum(["auto", "manual"]);
11118
+ /** Exposure mode. */
11119
+ var ExposureModeSchema = _enum(["auto", "manual"]);
11120
+ /**
11121
+ * Backlight-compensation mode:
11122
+ * - `off` — disabled
11123
+ * - `blc` — backlight compensation
11124
+ * - `wdr` — wide dynamic range
11125
+ * - `hlc` — highlight compensation
11126
+ */
11127
+ var BacklightModeSchema = _enum([
11128
+ "off",
11129
+ "blc",
11130
+ "wdr",
11131
+ "hlc"
11132
+ ]);
11133
+ /** Normalized numeric range descriptor — `{ min, max, step }` per the
11134
+ * getOptions availability convention. Slider values are normalized 0–100. */
11135
+ var NormalizedRangeSchema = object({
11136
+ min: number(),
11137
+ max: number(),
11138
+ step: number()
11139
+ });
11140
+ /**
11141
+ * Current image-adjustment state. Every field optional — absent when the
11142
+ * camera does not expose that control. Slider values are NORMALIZED 0–100.
11143
+ * `lastFetchedAt` feeds the runtime-state bridge.
11144
+ */
11145
+ var ImageSettingsStatusSchema = object({
11146
+ /** Normalized 0–100. */
11147
+ brightness: number().optional(),
11148
+ /** Normalized 0–100. */
11149
+ contrast: number().optional(),
11150
+ /** Normalized 0–100. */
11151
+ saturation: number().optional(),
11152
+ /** Normalized 0–100. */
11153
+ sharpness: number().optional(),
11154
+ mirror: boolean().optional(),
11155
+ flip: boolean().optional(),
11156
+ rotate: ImageRotateSchema.optional(),
11157
+ whiteBalance: WhiteBalanceModeSchema.optional(),
11158
+ /** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
11159
+ warmth: number().optional(),
11160
+ exposureMode: ExposureModeSchema.optional(),
11161
+ backlightMode: BacklightModeSchema.optional(),
11162
+ lastFetchedAt: number()
11163
+ });
11164
+ /**
11165
+ * Per-camera availability descriptor — drives which controls the admin UI
11166
+ * renders. Booleans as `supportsX`; numeric ranges as `{ min, max, step }`
11167
+ * (the normalized 0–100 range); enums as arrays of supported values (empty
11168
+ * array → control hidden). A provider returns honest, camera-probed values
11169
+ * — never hardcoded.
11170
+ */
11171
+ var ImageSettingsOptionsSchema = object({
11172
+ supportsBrightness: boolean(),
11173
+ brightness: NormalizedRangeSchema.optional(),
11174
+ supportsContrast: boolean(),
11175
+ contrast: NormalizedRangeSchema.optional(),
11176
+ supportsSaturation: boolean(),
11177
+ saturation: NormalizedRangeSchema.optional(),
11178
+ supportsSharpness: boolean(),
11179
+ sharpness: NormalizedRangeSchema.optional(),
11180
+ supportsMirror: boolean(),
11181
+ supportsFlip: boolean(),
11182
+ /** Supported rotation values. Empty → rotation not configurable. */
11183
+ rotateOptions: array(ImageRotateSchema),
11184
+ /** Supported white-balance modes. Empty → white-balance not configurable. */
11185
+ whiteBalanceModes: array(WhiteBalanceModeSchema),
11186
+ supportsWarmth: boolean(),
11187
+ /** Present when `supportsWarmth` — the normalized 0–100 range. */
11188
+ warmth: NormalizedRangeSchema.optional(),
11189
+ /** Supported exposure modes. Empty → exposure not configurable. */
11190
+ exposureModes: array(ExposureModeSchema),
11191
+ /** Supported backlight modes. Empty → backlight-compensation not configurable. */
11192
+ backlightModes: array(BacklightModeSchema)
11193
+ });
11194
+ /**
11195
+ * Partial change to the image config — every field optional. Slider values
11196
+ * are normalized 0–100. A provider ignores fields it does not support.
11197
+ */
11198
+ var ImageSettingsPatchSchema = object({
11199
+ brightness: number().optional(),
11200
+ contrast: number().optional(),
11201
+ saturation: number().optional(),
11202
+ sharpness: number().optional(),
11203
+ mirror: boolean().optional(),
11204
+ flip: boolean().optional(),
11205
+ rotate: ImageRotateSchema.optional(),
11206
+ whiteBalance: WhiteBalanceModeSchema.optional(),
11207
+ warmth: number().optional(),
11208
+ exposureMode: ExposureModeSchema.optional(),
11209
+ backlightMode: BacklightModeSchema.optional()
11210
+ });
11211
+ var imageSettingsCapability = {
11212
+ name: "image-settings",
11213
+ scope: "device",
11214
+ deviceNative: true,
11215
+ mode: "singleton",
11216
+ deviceTypes: [DeviceType.Camera],
11217
+ deviceConfig: { ui: {
11218
+ kind: "derived-form",
11219
+ builderId: "image-settings",
11220
+ tab: "image"
11221
+ } },
11222
+ methods: {
11223
+ getOptions: method(object({ deviceId: number() }), ImageSettingsOptionsSchema),
11224
+ setSettings: method(object({
11225
+ deviceId: number(),
11226
+ settings: ImageSettingsPatchSchema
11227
+ }), _void(), {
11228
+ kind: "mutation",
11229
+ auth: "admin"
11230
+ })
11231
+ },
11232
+ status: {
11233
+ schema: ImageSettingsStatusSchema,
11234
+ kind: "poll"
11235
+ },
11236
+ runtimeState: ImageSettingsStatusSchema
11237
+ };
11238
+ /**
10979
11239
  * Robotic lawn-mower cap. Models HA `lawn_mower.*` entities — anything
10980
11240
  * with a mowing lifecycle plus a dock action.
10981
11241
  *
@@ -11974,6 +12234,16 @@ var RunnerCameraConfigSchema = object({
11974
12234
  * this gate is bypassed.
11975
12235
  */
11976
12236
  onboardMotionDrivesAnalyzer: boolean().default(true),
12237
+ /**
12238
+ * Master toggle for the occupancy re-check. When `false` (DEFAULT) the runner
12239
+ * never arms the periodic recheck timer, regardless of `occupancyRecheckSec` —
12240
+ * this is off by default because the recheck re-subscribes a detection session
12241
+ * every N seconds while `watching`, a major source of pull-decoder re-dial
12242
+ * churn (each cycle creates+tears a session → RTSP re-dial → latency). The
12243
+ * `occupancyRecheckSec` / `occupancyRecheckFrames` sliders only take effect
12244
+ * (and only render) when this is enabled.
12245
+ */
12246
+ occupancyRecheckEnabled: boolean().default(false),
11977
12247
  occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
11978
12248
  occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
11979
12249
  /**
@@ -13979,6 +14249,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
13979
14249
  contact: contactCapability,
13980
14250
  control: controlCapability,
13981
14251
  cover: coverCapability,
14252
+ dayNight: dayNightCapability,
13982
14253
  deviceDiscovery: deviceDiscoveryCapability,
13983
14254
  deviceStatus: deviceStatusCapability,
13984
14255
  doorbell: doorbellCapability,
@@ -13991,6 +14262,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
13991
14262
  humidifier: humidifierCapability,
13992
14263
  humiditySensor: humiditySensorCapability,
13993
14264
  image: imageCapability,
14265
+ imageSettings: imageSettingsCapability,
13994
14266
  lawnMowerControl: lawnMowerControlCapability,
13995
14267
  lockControl: lockControlCapability,
13996
14268
  mediaPlayer: mediaPlayerCapability,
@@ -15905,7 +16177,9 @@ method(object({ codec: string() }), boolean()), method(_void(), object({
15905
16177
  id: string(),
15906
16178
  name: string(),
15907
16179
  isPullMode: boolean().optional(),
15908
- priority: number().optional()
16180
+ priority: number().optional(),
16181
+ hwaccel: string().optional(),
16182
+ probedBestHwaccel: string().optional()
15909
16183
  })), method(DecoderSessionConfigSchema, object({
15910
16184
  sessionId: string(),
15911
16185
  nodeId: string()
@@ -21914,6 +22188,18 @@ Object.freeze({
21914
22188
  addonId: null,
21915
22189
  access: "view"
21916
22190
  },
22191
+ "dayNight.getOptions": {
22192
+ capName: "day-night",
22193
+ capScope: "device",
22194
+ addonId: null,
22195
+ access: "view"
22196
+ },
22197
+ "dayNight.setSettings": {
22198
+ capName: "day-night",
22199
+ capScope: "device",
22200
+ addonId: null,
22201
+ access: "create"
22202
+ },
21917
22203
  "decoder.createSession": {
21918
22204
  capName: "decoder",
21919
22205
  capScope: "system",
@@ -22844,6 +23130,18 @@ Object.freeze({
22844
23130
  addonId: null,
22845
23131
  access: "create"
22846
23132
  },
23133
+ "imageSettings.getOptions": {
23134
+ capName: "image-settings",
23135
+ capScope: "device",
23136
+ addonId: null,
23137
+ access: "view"
23138
+ },
23139
+ "imageSettings.setSettings": {
23140
+ capName: "image-settings",
23141
+ capScope: "device",
23142
+ addonId: null,
23143
+ access: "create"
23144
+ },
22847
23145
  "integrations.create": {
22848
23146
  capName: "integrations",
22849
23147
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-unraid",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Unraid device-provider addon for CamStack — one Container per Unraid instance fanning out array, disk, docker and notification entities",
5
5
  "keywords": [
6
6
  "camstack",