@camstack/addon-provider-hikvision 1.2.152 → 1.2.154

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
@@ -5440,7 +5440,7 @@ var ZodIssueCode = {
5440
5440
  var ZodFirstPartyTypeKind;
5441
5441
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5442
5442
  //#endregion
5443
- //#region ../types/dist/sleep-bZIhUvjd.mjs
5443
+ //#region ../types/dist/sleep-BegKjwUu.mjs
5444
5444
  /**
5445
5445
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5446
5446
  * window to float samples (D455).
@@ -8485,7 +8485,7 @@ function userError(code, params, englishFallback) {
8485
8485
  return new CamstackError(code, params, englishFallback);
8486
8486
  }
8487
8487
  //#endregion
8488
- //#region ../types/dist/err-msg--2RrYiLO.mjs
8488
+ //#region ../types/dist/err-msg-BXKzRBwg.mjs
8489
8489
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
8490
8490
  DeviceType["Camera"] = "camera";
8491
8491
  DeviceType["Hub"] = "hub";
@@ -8577,6 +8577,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
8577
8577
  * native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
8578
8578
  * integrations sharing the same food/desiccant/hopper surface. */
8579
8579
  DeviceType["PetFeeder"] = "pet-feeder";
8580
+ /** Built-in dishwasher — program lifecycle, door / remote-start gates,
8581
+ * salt and rinse-aid levels. Installed with the `dishwasher` cap.
8582
+ * Sources: native Bosch Home Connect, reusable by similar integrations. */
8583
+ DeviceType["Dishwasher"] = "dishwasher";
8580
8584
  return DeviceType;
8581
8585
  }({});
8582
8586
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -8824,7 +8828,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
8824
8828
  return DeviceRole;
8825
8829
  }({});
8826
8830
  //#endregion
8827
- //#region ../types/dist/composition-DOwQB_Ua.mjs
8831
+ //#region ../types/dist/composition-CB6PMT9p.mjs
8828
8832
  /**
8829
8833
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8830
8834
  *
@@ -13511,8 +13515,13 @@ var AlertSeveritySchema = _enum([
13511
13515
  "info",
13512
13516
  "success",
13513
13517
  "warning",
13514
- "error"
13518
+ "error",
13519
+ "critical"
13515
13520
  ]);
13521
+ var AlertActionSchema = object({
13522
+ label: string(),
13523
+ href: string().optional()
13524
+ });
13516
13525
  var AlertStatusSchema = _enum([
13517
13526
  "active",
13518
13527
  "in-progress",
@@ -13530,6 +13539,7 @@ var AlertSchema = object({
13530
13539
  severity: AlertSeveritySchema,
13531
13540
  title: string(),
13532
13541
  message: string(),
13542
+ action: AlertActionSchema.optional(),
13533
13543
  status: AlertStatusSchema,
13534
13544
  progress: number().optional(),
13535
13545
  read: boolean(),
@@ -18004,7 +18014,11 @@ var deviceDiscoveryCapability = {
18004
18014
  };
18005
18015
  /**
18006
18016
  * `device-adoption` — generic discovery + adoption surface,
18007
- * system-scoped singleton. The de-HA-ified successor to `ha-discovery`:
18017
+ * system-scoped collection (one provider per integration addon), routed
18018
+ * by explicit `{ addonId }` on direct `deviceAdoption.*` calls — the same
18019
+ * pin model as `connection-test`. The admin UI keeps using
18020
+ * `deviceManager.adoption*` (which already threads `addonId`). The de-HA-ified
18021
+ * successor to `ha-discovery`:
18008
18022
  * keyed by `integrationId` (the addon resolves integrationId → broker
18009
18023
  * internally) rather than a connection-specific `brokerId`, and it
18010
18024
  * REUSES the shared `DiscoveredChildDevice` candidate type from
@@ -54725,7 +54739,8 @@ var batteryCapability = {
54725
54739
  DeviceType.Button,
54726
54740
  DeviceType.Switch,
54727
54741
  DeviceType.PetFeeder,
54728
- DeviceType.Container
54742
+ DeviceType.Container,
54743
+ DeviceType.Thermostat
54729
54744
  ],
54730
54745
  methods: {
54731
54746
  /**
@@ -56198,6 +56213,161 @@ onStatusChanged: { data: object({
56198
56213
  * whether persisting is worth a SQLite commit. */
56199
56214
  volatileStateFields: ["lastChangedAt"]
56200
56215
  };
56216
+ /**
56217
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
56218
+ * consumable levels (salt, rinse aid) and common program options.
56219
+ *
56220
+ * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
56221
+ * by any integration that exposes the same program / option surface.
56222
+ *
56223
+ * `kind: 'poll'` — cloud REST APIs typically have no push channel; the
56224
+ * provider refreshes the slice on an interval and eagerly after commands.
56225
+ */
56226
+ var DishwasherStateSchema = _enum([
56227
+ "idle",
56228
+ "running",
56229
+ "paused",
56230
+ "finished",
56231
+ "error",
56232
+ "unavailable"
56233
+ ]);
56234
+ var DishwasherConsumableLevelSchema = _enum([
56235
+ "ok",
56236
+ "low",
56237
+ "empty"
56238
+ ]);
56239
+ var DishwasherStatusSchema = object({
56240
+ state: DishwasherStateSchema,
56241
+ /** Active program id/name, or null when none selected / unknown. */
56242
+ program: string().nullable(),
56243
+ /** Program tokens the hardware accepts — drives the UI selector. */
56244
+ availablePrograms: array(string()),
56245
+ /** Minutes remaining on the active cycle, or null when not running. */
56246
+ remainingMinutes: number().int().nonnegative().nullable(),
56247
+ /** Cycle completion 0..100, or null when not applicable. */
56248
+ progressPercent: number().min(0).max(100).nullable(),
56249
+ /** True when the door is reported open. */
56250
+ doorOpen: boolean(),
56251
+ /** True when remote start is allowed (door closed, power on, etc.). */
56252
+ remoteStartAllowed: boolean(),
56253
+ /** Main power / switched-on state. */
56254
+ powerOn: boolean(),
56255
+ saltLevel: DishwasherConsumableLevelSchema.nullable(),
56256
+ rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
56257
+ halfLoad: boolean(),
56258
+ hygienePlus: boolean(),
56259
+ /** Extra dry option when the appliance exposes it. */
56260
+ extraDry: boolean(),
56261
+ /** Intensive zone (lower basket) when the appliance exposes it. */
56262
+ intensiveZone: boolean(),
56263
+ /** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
56264
+ varioSpeedPlus: boolean(),
56265
+ /** Child lock (controls disabled on the appliance). */
56266
+ childLock: boolean(),
56267
+ errorCode: number().nullable(),
56268
+ errorLabel: string().nullable(),
56269
+ lastFetchedAt: number()
56270
+ });
56271
+ var dishwasherCapability = {
56272
+ name: "dishwasher",
56273
+ scope: "device",
56274
+ deviceNative: true,
56275
+ mode: "singleton",
56276
+ deviceTypes: [DeviceType.Dishwasher],
56277
+ methods: {
56278
+ start: method(object({ deviceId: number().int().nonnegative() }), _void(), {
56279
+ kind: "mutation",
56280
+ auth: "protected"
56281
+ }),
56282
+ pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
56283
+ kind: "mutation",
56284
+ auth: "protected"
56285
+ }),
56286
+ stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
56287
+ kind: "mutation",
56288
+ auth: "protected"
56289
+ }),
56290
+ setProgram: method(object({
56291
+ deviceId: number().int().nonnegative(),
56292
+ program: string().min(1)
56293
+ }), _void(), {
56294
+ kind: "mutation",
56295
+ auth: "protected"
56296
+ }),
56297
+ setPower: method(object({
56298
+ deviceId: number().int().nonnegative(),
56299
+ on: boolean()
56300
+ }), _void(), {
56301
+ kind: "mutation",
56302
+ auth: "protected"
56303
+ }),
56304
+ setHalfLoad: method(object({
56305
+ deviceId: number().int().nonnegative(),
56306
+ on: boolean()
56307
+ }), _void(), {
56308
+ kind: "mutation",
56309
+ auth: "protected"
56310
+ }),
56311
+ setHygienePlus: method(object({
56312
+ deviceId: number().int().nonnegative(),
56313
+ on: boolean()
56314
+ }), _void(), {
56315
+ kind: "mutation",
56316
+ auth: "protected"
56317
+ }),
56318
+ setExtraDry: method(object({
56319
+ deviceId: number().int().nonnegative(),
56320
+ on: boolean()
56321
+ }), _void(), {
56322
+ kind: "mutation",
56323
+ auth: "protected"
56324
+ }),
56325
+ setIntensiveZone: method(object({
56326
+ deviceId: number().int().nonnegative(),
56327
+ on: boolean()
56328
+ }), _void(), {
56329
+ kind: "mutation",
56330
+ auth: "protected"
56331
+ }),
56332
+ setVarioSpeedPlus: method(object({
56333
+ deviceId: number().int().nonnegative(),
56334
+ on: boolean()
56335
+ }), _void(), {
56336
+ kind: "mutation",
56337
+ auth: "protected"
56338
+ }),
56339
+ setChildLock: method(object({
56340
+ deviceId: number().int().nonnegative(),
56341
+ on: boolean()
56342
+ }), _void(), {
56343
+ kind: "mutation",
56344
+ auth: "protected"
56345
+ }),
56346
+ setOption: method(object({
56347
+ deviceId: number().int().nonnegative(),
56348
+ key: string().min(1),
56349
+ value: union([
56350
+ boolean(),
56351
+ string(),
56352
+ number()
56353
+ ])
56354
+ }), _void(), {
56355
+ kind: "mutation",
56356
+ auth: "protected"
56357
+ })
56358
+ },
56359
+ status: {
56360
+ schema: DishwasherStatusSchema,
56361
+ kind: "poll"
56362
+ },
56363
+ runtimeState: DishwasherStatusSchema,
56364
+ durability: "session",
56365
+ history: { fields: { progressPercent: {
56366
+ kind: "gauge",
56367
+ unit: "%",
56368
+ deadband: 2
56369
+ } } }
56370
+ };
56201
56371
  var DoorbellStatusSchema = object({
56202
56372
  /** Ms epoch of the last press. null = never observed since this provider started. */
56203
56373
  lastPressedAt: number().nullable(),
@@ -57000,6 +57170,32 @@ var gasCapability = {
57000
57170
  * whether persisting is worth a SQLite commit. */
57001
57171
  volatileStateFields: ["lastChangedAt"]
57002
57172
  };
57173
+ var HeatingValveStatusSchema = object({
57174
+ /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
57175
+ position: number().min(0).max(100).nullable(),
57176
+ /** Ms epoch when the slice was last updated (push or poll). */
57177
+ lastFetchedAt: number()
57178
+ });
57179
+ var heatingValveCapability = {
57180
+ name: "heating-valve",
57181
+ scope: "device",
57182
+ deviceNative: true,
57183
+ mode: "singleton",
57184
+ deviceTypes: [DeviceType.Thermostat],
57185
+ methods: {},
57186
+ status: {
57187
+ schema: HeatingValveStatusSchema,
57188
+ kind: "push"
57189
+ },
57190
+ runtimeState: HeatingValveStatusSchema,
57191
+ durability: "session",
57192
+ history: { fields: { position: {
57193
+ kind: "gauge",
57194
+ unit: "%",
57195
+ deadband: 1
57196
+ } } },
57197
+ volatileStateFields: ["lastFetchedAt"]
57198
+ };
57003
57199
  /**
57004
57200
  * Humidifier / dehumidifier cap. Models HA `humidifier.*` entities —
57005
57201
  * an on/off actuator with an optional target-humidity setpoint and an
@@ -66996,6 +67192,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
66996
67192
  dayNight: dayNightCapability,
66997
67193
  deviceDiscovery: deviceDiscoveryCapability,
66998
67194
  deviceStatus: deviceStatusCapability,
67195
+ dishwasher: dishwasherCapability,
66999
67196
  doorbell: doorbellCapability,
67000
67197
  enumSensor: enumSensorCapability,
67001
67198
  eventEmitter: eventEmitterCapability,
@@ -67003,6 +67200,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
67003
67200
  featureProbe: featureProbeCapability,
67004
67201
  flood: floodCapability,
67005
67202
  gas: gasCapability,
67203
+ heatingValve: heatingValveCapability,
67006
67204
  humidifier: humidifierCapability,
67007
67205
  humiditySensor: humiditySensorCapability,
67008
67206
  image: imageCapability,
@@ -67728,6 +67926,12 @@ var BaseDeviceProvider = class extends BaseAddon {
67728
67926
  provider: this
67729
67927
  }];
67730
67928
  }
67929
+ /** Flatten `super.onInitialize()` whether it returned an array or an envelope. */
67930
+ providerRegistrationsFromSuper(result) {
67931
+ if (Array.isArray(result)) return result;
67932
+ if (result !== void 0 && result.providers !== void 0) return [...result.providers];
67933
+ return [];
67934
+ }
67731
67935
  async onShutdown() {
67732
67936
  this._restoreShuttingDown = true;
67733
67937
  this.cancelRestoreRetries();
@@ -68258,7 +68462,7 @@ var BaseDeviceProvider = class extends BaseAddon {
68258
68462
  function widenDeviceConstructor(ctor) {
68259
68463
  return ctor;
68260
68464
  }
68261
- DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
68465
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
68262
68466
  new Set(Object.values(DeviceType));
68263
68467
  Object.freeze({
68264
68468
  "accessories.getStatus": {
@@ -70679,6 +70883,84 @@ Object.freeze({
70679
70883
  addonId: null,
70680
70884
  access: "view"
70681
70885
  },
70886
+ "dishwasher.getStatus": {
70887
+ capName: "dishwasher",
70888
+ capScope: "device",
70889
+ addonId: null,
70890
+ access: "view"
70891
+ },
70892
+ "dishwasher.pause": {
70893
+ capName: "dishwasher",
70894
+ capScope: "device",
70895
+ addonId: null,
70896
+ access: "create"
70897
+ },
70898
+ "dishwasher.setChildLock": {
70899
+ capName: "dishwasher",
70900
+ capScope: "device",
70901
+ addonId: null,
70902
+ access: "create"
70903
+ },
70904
+ "dishwasher.setExtraDry": {
70905
+ capName: "dishwasher",
70906
+ capScope: "device",
70907
+ addonId: null,
70908
+ access: "create"
70909
+ },
70910
+ "dishwasher.setHalfLoad": {
70911
+ capName: "dishwasher",
70912
+ capScope: "device",
70913
+ addonId: null,
70914
+ access: "create"
70915
+ },
70916
+ "dishwasher.setHygienePlus": {
70917
+ capName: "dishwasher",
70918
+ capScope: "device",
70919
+ addonId: null,
70920
+ access: "create"
70921
+ },
70922
+ "dishwasher.setIntensiveZone": {
70923
+ capName: "dishwasher",
70924
+ capScope: "device",
70925
+ addonId: null,
70926
+ access: "create"
70927
+ },
70928
+ "dishwasher.setOption": {
70929
+ capName: "dishwasher",
70930
+ capScope: "device",
70931
+ addonId: null,
70932
+ access: "create"
70933
+ },
70934
+ "dishwasher.setPower": {
70935
+ capName: "dishwasher",
70936
+ capScope: "device",
70937
+ addonId: null,
70938
+ access: "create"
70939
+ },
70940
+ "dishwasher.setProgram": {
70941
+ capName: "dishwasher",
70942
+ capScope: "device",
70943
+ addonId: null,
70944
+ access: "create"
70945
+ },
70946
+ "dishwasher.setVarioSpeedPlus": {
70947
+ capName: "dishwasher",
70948
+ capScope: "device",
70949
+ addonId: null,
70950
+ access: "create"
70951
+ },
70952
+ "dishwasher.start": {
70953
+ capName: "dishwasher",
70954
+ capScope: "device",
70955
+ addonId: null,
70956
+ access: "create"
70957
+ },
70958
+ "dishwasher.stop": {
70959
+ capName: "dishwasher",
70960
+ capScope: "device",
70961
+ addonId: null,
70962
+ access: "create"
70963
+ },
70682
70964
  "doorbell.getStatus": {
70683
70965
  capName: "doorbell",
70684
70966
  capScope: "device",
@@ -70889,6 +71171,12 @@ Object.freeze({
70889
71171
  addonId: null,
70890
71172
  access: "view"
70891
71173
  },
71174
+ "heatingValve.getStatus": {
71175
+ capName: "heating-valve",
71176
+ capScope: "device",
71177
+ addonId: null,
71178
+ access: "view"
71179
+ },
70892
71180
  "humidifier.getStatus": {
70893
71181
  capName: "humidifier",
70894
71182
  capScope: "device",
@@ -76476,7 +76764,7 @@ Object.freeze({
76476
76764
  access: "create"
76477
76765
  }
76478
76766
  });
76479
- DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
76767
+ DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
76480
76768
  DeviceFeature.BatteryOperated;
76481
76769
  /** Reject after `ms`; always clears its own timer. */
76482
76770
  async function withTimeout$1(promise, ms, label) {
@@ -77518,6 +77806,71 @@ Object.freeze({
77518
77806
  form: "single",
77519
77807
  optional: false
77520
77808
  }],
77809
+ "dishwasher.getStatus": [{
77810
+ name: "deviceId",
77811
+ form: "single",
77812
+ optional: false
77813
+ }],
77814
+ "dishwasher.pause": [{
77815
+ name: "deviceId",
77816
+ form: "single",
77817
+ optional: false
77818
+ }],
77819
+ "dishwasher.setChildLock": [{
77820
+ name: "deviceId",
77821
+ form: "single",
77822
+ optional: false
77823
+ }],
77824
+ "dishwasher.setExtraDry": [{
77825
+ name: "deviceId",
77826
+ form: "single",
77827
+ optional: false
77828
+ }],
77829
+ "dishwasher.setHalfLoad": [{
77830
+ name: "deviceId",
77831
+ form: "single",
77832
+ optional: false
77833
+ }],
77834
+ "dishwasher.setHygienePlus": [{
77835
+ name: "deviceId",
77836
+ form: "single",
77837
+ optional: false
77838
+ }],
77839
+ "dishwasher.setIntensiveZone": [{
77840
+ name: "deviceId",
77841
+ form: "single",
77842
+ optional: false
77843
+ }],
77844
+ "dishwasher.setOption": [{
77845
+ name: "deviceId",
77846
+ form: "single",
77847
+ optional: false
77848
+ }],
77849
+ "dishwasher.setPower": [{
77850
+ name: "deviceId",
77851
+ form: "single",
77852
+ optional: false
77853
+ }],
77854
+ "dishwasher.setProgram": [{
77855
+ name: "deviceId",
77856
+ form: "single",
77857
+ optional: false
77858
+ }],
77859
+ "dishwasher.setVarioSpeedPlus": [{
77860
+ name: "deviceId",
77861
+ form: "single",
77862
+ optional: false
77863
+ }],
77864
+ "dishwasher.start": [{
77865
+ name: "deviceId",
77866
+ form: "single",
77867
+ optional: false
77868
+ }],
77869
+ "dishwasher.stop": [{
77870
+ name: "deviceId",
77871
+ form: "single",
77872
+ optional: false
77873
+ }],
77521
77874
  "doorbell.getStatus": [{
77522
77875
  name: "deviceId",
77523
77876
  form: "single",
@@ -77587,6 +77940,11 @@ Object.freeze({
77587
77940
  form: "single",
77588
77941
  optional: false
77589
77942
  }],
77943
+ "heatingValve.getStatus": [{
77944
+ name: "deviceId",
77945
+ form: "single",
77946
+ optional: false
77947
+ }],
77590
77948
  "humidifier.getStatus": [{
77591
77949
  name: "deviceId",
77592
77950
  form: "single",
@@ -103188,7 +103546,7 @@ var HikvisionProviderAddon = class extends BaseDeviceProvider {
103188
103546
  throw new Error(`Hikvision: ${reason}`);
103189
103547
  }
103190
103548
  async onInitialize() {
103191
- const regs = await super.onInitialize();
103549
+ const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
103192
103550
  regs.push({
103193
103551
  capability: failureContributionCapability,
103194
103552
  provider: { list: () => intercomFailureReport.list() }
package/dist/addon.mjs CHANGED
@@ -5419,7 +5419,7 @@ var ZodIssueCode = {
5419
5419
  var ZodFirstPartyTypeKind;
5420
5420
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5421
5421
  //#endregion
5422
- //#region ../types/dist/sleep-bZIhUvjd.mjs
5422
+ //#region ../types/dist/sleep-BegKjwUu.mjs
5423
5423
  /**
5424
5424
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5425
5425
  * window to float samples (D455).
@@ -8464,7 +8464,7 @@ function userError(code, params, englishFallback) {
8464
8464
  return new CamstackError(code, params, englishFallback);
8465
8465
  }
8466
8466
  //#endregion
8467
- //#region ../types/dist/err-msg--2RrYiLO.mjs
8467
+ //#region ../types/dist/err-msg-BXKzRBwg.mjs
8468
8468
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
8469
8469
  DeviceType["Camera"] = "camera";
8470
8470
  DeviceType["Hub"] = "hub";
@@ -8556,6 +8556,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
8556
8556
  * native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
8557
8557
  * integrations sharing the same food/desiccant/hopper surface. */
8558
8558
  DeviceType["PetFeeder"] = "pet-feeder";
8559
+ /** Built-in dishwasher — program lifecycle, door / remote-start gates,
8560
+ * salt and rinse-aid levels. Installed with the `dishwasher` cap.
8561
+ * Sources: native Bosch Home Connect, reusable by similar integrations. */
8562
+ DeviceType["Dishwasher"] = "dishwasher";
8559
8563
  return DeviceType;
8560
8564
  }({});
8561
8565
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -8803,7 +8807,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
8803
8807
  return DeviceRole;
8804
8808
  }({});
8805
8809
  //#endregion
8806
- //#region ../types/dist/composition-DOwQB_Ua.mjs
8810
+ //#region ../types/dist/composition-CB6PMT9p.mjs
8807
8811
  /**
8808
8812
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8809
8813
  *
@@ -13490,8 +13494,13 @@ var AlertSeveritySchema = _enum([
13490
13494
  "info",
13491
13495
  "success",
13492
13496
  "warning",
13493
- "error"
13497
+ "error",
13498
+ "critical"
13494
13499
  ]);
13500
+ var AlertActionSchema = object({
13501
+ label: string(),
13502
+ href: string().optional()
13503
+ });
13495
13504
  var AlertStatusSchema = _enum([
13496
13505
  "active",
13497
13506
  "in-progress",
@@ -13509,6 +13518,7 @@ var AlertSchema = object({
13509
13518
  severity: AlertSeveritySchema,
13510
13519
  title: string(),
13511
13520
  message: string(),
13521
+ action: AlertActionSchema.optional(),
13512
13522
  status: AlertStatusSchema,
13513
13523
  progress: number().optional(),
13514
13524
  read: boolean(),
@@ -17983,7 +17993,11 @@ var deviceDiscoveryCapability = {
17983
17993
  };
17984
17994
  /**
17985
17995
  * `device-adoption` — generic discovery + adoption surface,
17986
- * system-scoped singleton. The de-HA-ified successor to `ha-discovery`:
17996
+ * system-scoped collection (one provider per integration addon), routed
17997
+ * by explicit `{ addonId }` on direct `deviceAdoption.*` calls — the same
17998
+ * pin model as `connection-test`. The admin UI keeps using
17999
+ * `deviceManager.adoption*` (which already threads `addonId`). The de-HA-ified
18000
+ * successor to `ha-discovery`:
17987
18001
  * keyed by `integrationId` (the addon resolves integrationId → broker
17988
18002
  * internally) rather than a connection-specific `brokerId`, and it
17989
18003
  * REUSES the shared `DiscoveredChildDevice` candidate type from
@@ -54704,7 +54718,8 @@ var batteryCapability = {
54704
54718
  DeviceType.Button,
54705
54719
  DeviceType.Switch,
54706
54720
  DeviceType.PetFeeder,
54707
- DeviceType.Container
54721
+ DeviceType.Container,
54722
+ DeviceType.Thermostat
54708
54723
  ],
54709
54724
  methods: {
54710
54725
  /**
@@ -56177,6 +56192,161 @@ onStatusChanged: { data: object({
56177
56192
  * whether persisting is worth a SQLite commit. */
56178
56193
  volatileStateFields: ["lastChangedAt"]
56179
56194
  };
56195
+ /**
56196
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
56197
+ * consumable levels (salt, rinse aid) and common program options.
56198
+ *
56199
+ * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
56200
+ * by any integration that exposes the same program / option surface.
56201
+ *
56202
+ * `kind: 'poll'` — cloud REST APIs typically have no push channel; the
56203
+ * provider refreshes the slice on an interval and eagerly after commands.
56204
+ */
56205
+ var DishwasherStateSchema = _enum([
56206
+ "idle",
56207
+ "running",
56208
+ "paused",
56209
+ "finished",
56210
+ "error",
56211
+ "unavailable"
56212
+ ]);
56213
+ var DishwasherConsumableLevelSchema = _enum([
56214
+ "ok",
56215
+ "low",
56216
+ "empty"
56217
+ ]);
56218
+ var DishwasherStatusSchema = object({
56219
+ state: DishwasherStateSchema,
56220
+ /** Active program id/name, or null when none selected / unknown. */
56221
+ program: string().nullable(),
56222
+ /** Program tokens the hardware accepts — drives the UI selector. */
56223
+ availablePrograms: array(string()),
56224
+ /** Minutes remaining on the active cycle, or null when not running. */
56225
+ remainingMinutes: number().int().nonnegative().nullable(),
56226
+ /** Cycle completion 0..100, or null when not applicable. */
56227
+ progressPercent: number().min(0).max(100).nullable(),
56228
+ /** True when the door is reported open. */
56229
+ doorOpen: boolean(),
56230
+ /** True when remote start is allowed (door closed, power on, etc.). */
56231
+ remoteStartAllowed: boolean(),
56232
+ /** Main power / switched-on state. */
56233
+ powerOn: boolean(),
56234
+ saltLevel: DishwasherConsumableLevelSchema.nullable(),
56235
+ rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
56236
+ halfLoad: boolean(),
56237
+ hygienePlus: boolean(),
56238
+ /** Extra dry option when the appliance exposes it. */
56239
+ extraDry: boolean(),
56240
+ /** Intensive zone (lower basket) when the appliance exposes it. */
56241
+ intensiveZone: boolean(),
56242
+ /** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
56243
+ varioSpeedPlus: boolean(),
56244
+ /** Child lock (controls disabled on the appliance). */
56245
+ childLock: boolean(),
56246
+ errorCode: number().nullable(),
56247
+ errorLabel: string().nullable(),
56248
+ lastFetchedAt: number()
56249
+ });
56250
+ var dishwasherCapability = {
56251
+ name: "dishwasher",
56252
+ scope: "device",
56253
+ deviceNative: true,
56254
+ mode: "singleton",
56255
+ deviceTypes: [DeviceType.Dishwasher],
56256
+ methods: {
56257
+ start: method(object({ deviceId: number().int().nonnegative() }), _void(), {
56258
+ kind: "mutation",
56259
+ auth: "protected"
56260
+ }),
56261
+ pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
56262
+ kind: "mutation",
56263
+ auth: "protected"
56264
+ }),
56265
+ stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
56266
+ kind: "mutation",
56267
+ auth: "protected"
56268
+ }),
56269
+ setProgram: method(object({
56270
+ deviceId: number().int().nonnegative(),
56271
+ program: string().min(1)
56272
+ }), _void(), {
56273
+ kind: "mutation",
56274
+ auth: "protected"
56275
+ }),
56276
+ setPower: method(object({
56277
+ deviceId: number().int().nonnegative(),
56278
+ on: boolean()
56279
+ }), _void(), {
56280
+ kind: "mutation",
56281
+ auth: "protected"
56282
+ }),
56283
+ setHalfLoad: method(object({
56284
+ deviceId: number().int().nonnegative(),
56285
+ on: boolean()
56286
+ }), _void(), {
56287
+ kind: "mutation",
56288
+ auth: "protected"
56289
+ }),
56290
+ setHygienePlus: method(object({
56291
+ deviceId: number().int().nonnegative(),
56292
+ on: boolean()
56293
+ }), _void(), {
56294
+ kind: "mutation",
56295
+ auth: "protected"
56296
+ }),
56297
+ setExtraDry: method(object({
56298
+ deviceId: number().int().nonnegative(),
56299
+ on: boolean()
56300
+ }), _void(), {
56301
+ kind: "mutation",
56302
+ auth: "protected"
56303
+ }),
56304
+ setIntensiveZone: method(object({
56305
+ deviceId: number().int().nonnegative(),
56306
+ on: boolean()
56307
+ }), _void(), {
56308
+ kind: "mutation",
56309
+ auth: "protected"
56310
+ }),
56311
+ setVarioSpeedPlus: method(object({
56312
+ deviceId: number().int().nonnegative(),
56313
+ on: boolean()
56314
+ }), _void(), {
56315
+ kind: "mutation",
56316
+ auth: "protected"
56317
+ }),
56318
+ setChildLock: method(object({
56319
+ deviceId: number().int().nonnegative(),
56320
+ on: boolean()
56321
+ }), _void(), {
56322
+ kind: "mutation",
56323
+ auth: "protected"
56324
+ }),
56325
+ setOption: method(object({
56326
+ deviceId: number().int().nonnegative(),
56327
+ key: string().min(1),
56328
+ value: union([
56329
+ boolean(),
56330
+ string(),
56331
+ number()
56332
+ ])
56333
+ }), _void(), {
56334
+ kind: "mutation",
56335
+ auth: "protected"
56336
+ })
56337
+ },
56338
+ status: {
56339
+ schema: DishwasherStatusSchema,
56340
+ kind: "poll"
56341
+ },
56342
+ runtimeState: DishwasherStatusSchema,
56343
+ durability: "session",
56344
+ history: { fields: { progressPercent: {
56345
+ kind: "gauge",
56346
+ unit: "%",
56347
+ deadband: 2
56348
+ } } }
56349
+ };
56180
56350
  var DoorbellStatusSchema = object({
56181
56351
  /** Ms epoch of the last press. null = never observed since this provider started. */
56182
56352
  lastPressedAt: number().nullable(),
@@ -56979,6 +57149,32 @@ var gasCapability = {
56979
57149
  * whether persisting is worth a SQLite commit. */
56980
57150
  volatileStateFields: ["lastChangedAt"]
56981
57151
  };
57152
+ var HeatingValveStatusSchema = object({
57153
+ /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
57154
+ position: number().min(0).max(100).nullable(),
57155
+ /** Ms epoch when the slice was last updated (push or poll). */
57156
+ lastFetchedAt: number()
57157
+ });
57158
+ var heatingValveCapability = {
57159
+ name: "heating-valve",
57160
+ scope: "device",
57161
+ deviceNative: true,
57162
+ mode: "singleton",
57163
+ deviceTypes: [DeviceType.Thermostat],
57164
+ methods: {},
57165
+ status: {
57166
+ schema: HeatingValveStatusSchema,
57167
+ kind: "push"
57168
+ },
57169
+ runtimeState: HeatingValveStatusSchema,
57170
+ durability: "session",
57171
+ history: { fields: { position: {
57172
+ kind: "gauge",
57173
+ unit: "%",
57174
+ deadband: 1
57175
+ } } },
57176
+ volatileStateFields: ["lastFetchedAt"]
57177
+ };
56982
57178
  /**
56983
57179
  * Humidifier / dehumidifier cap. Models HA `humidifier.*` entities —
56984
57180
  * an on/off actuator with an optional target-humidity setpoint and an
@@ -66975,6 +67171,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
66975
67171
  dayNight: dayNightCapability,
66976
67172
  deviceDiscovery: deviceDiscoveryCapability,
66977
67173
  deviceStatus: deviceStatusCapability,
67174
+ dishwasher: dishwasherCapability,
66978
67175
  doorbell: doorbellCapability,
66979
67176
  enumSensor: enumSensorCapability,
66980
67177
  eventEmitter: eventEmitterCapability,
@@ -66982,6 +67179,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
66982
67179
  featureProbe: featureProbeCapability,
66983
67180
  flood: floodCapability,
66984
67181
  gas: gasCapability,
67182
+ heatingValve: heatingValveCapability,
66985
67183
  humidifier: humidifierCapability,
66986
67184
  humiditySensor: humiditySensorCapability,
66987
67185
  image: imageCapability,
@@ -67707,6 +67905,12 @@ var BaseDeviceProvider = class extends BaseAddon {
67707
67905
  provider: this
67708
67906
  }];
67709
67907
  }
67908
+ /** Flatten `super.onInitialize()` whether it returned an array or an envelope. */
67909
+ providerRegistrationsFromSuper(result) {
67910
+ if (Array.isArray(result)) return result;
67911
+ if (result !== void 0 && result.providers !== void 0) return [...result.providers];
67912
+ return [];
67913
+ }
67710
67914
  async onShutdown() {
67711
67915
  this._restoreShuttingDown = true;
67712
67916
  this.cancelRestoreRetries();
@@ -68237,7 +68441,7 @@ var BaseDeviceProvider = class extends BaseAddon {
68237
68441
  function widenDeviceConstructor(ctor) {
68238
68442
  return ctor;
68239
68443
  }
68240
- DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
68444
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
68241
68445
  new Set(Object.values(DeviceType));
68242
68446
  Object.freeze({
68243
68447
  "accessories.getStatus": {
@@ -70658,6 +70862,84 @@ Object.freeze({
70658
70862
  addonId: null,
70659
70863
  access: "view"
70660
70864
  },
70865
+ "dishwasher.getStatus": {
70866
+ capName: "dishwasher",
70867
+ capScope: "device",
70868
+ addonId: null,
70869
+ access: "view"
70870
+ },
70871
+ "dishwasher.pause": {
70872
+ capName: "dishwasher",
70873
+ capScope: "device",
70874
+ addonId: null,
70875
+ access: "create"
70876
+ },
70877
+ "dishwasher.setChildLock": {
70878
+ capName: "dishwasher",
70879
+ capScope: "device",
70880
+ addonId: null,
70881
+ access: "create"
70882
+ },
70883
+ "dishwasher.setExtraDry": {
70884
+ capName: "dishwasher",
70885
+ capScope: "device",
70886
+ addonId: null,
70887
+ access: "create"
70888
+ },
70889
+ "dishwasher.setHalfLoad": {
70890
+ capName: "dishwasher",
70891
+ capScope: "device",
70892
+ addonId: null,
70893
+ access: "create"
70894
+ },
70895
+ "dishwasher.setHygienePlus": {
70896
+ capName: "dishwasher",
70897
+ capScope: "device",
70898
+ addonId: null,
70899
+ access: "create"
70900
+ },
70901
+ "dishwasher.setIntensiveZone": {
70902
+ capName: "dishwasher",
70903
+ capScope: "device",
70904
+ addonId: null,
70905
+ access: "create"
70906
+ },
70907
+ "dishwasher.setOption": {
70908
+ capName: "dishwasher",
70909
+ capScope: "device",
70910
+ addonId: null,
70911
+ access: "create"
70912
+ },
70913
+ "dishwasher.setPower": {
70914
+ capName: "dishwasher",
70915
+ capScope: "device",
70916
+ addonId: null,
70917
+ access: "create"
70918
+ },
70919
+ "dishwasher.setProgram": {
70920
+ capName: "dishwasher",
70921
+ capScope: "device",
70922
+ addonId: null,
70923
+ access: "create"
70924
+ },
70925
+ "dishwasher.setVarioSpeedPlus": {
70926
+ capName: "dishwasher",
70927
+ capScope: "device",
70928
+ addonId: null,
70929
+ access: "create"
70930
+ },
70931
+ "dishwasher.start": {
70932
+ capName: "dishwasher",
70933
+ capScope: "device",
70934
+ addonId: null,
70935
+ access: "create"
70936
+ },
70937
+ "dishwasher.stop": {
70938
+ capName: "dishwasher",
70939
+ capScope: "device",
70940
+ addonId: null,
70941
+ access: "create"
70942
+ },
70661
70943
  "doorbell.getStatus": {
70662
70944
  capName: "doorbell",
70663
70945
  capScope: "device",
@@ -70868,6 +71150,12 @@ Object.freeze({
70868
71150
  addonId: null,
70869
71151
  access: "view"
70870
71152
  },
71153
+ "heatingValve.getStatus": {
71154
+ capName: "heating-valve",
71155
+ capScope: "device",
71156
+ addonId: null,
71157
+ access: "view"
71158
+ },
70871
71159
  "humidifier.getStatus": {
70872
71160
  capName: "humidifier",
70873
71161
  capScope: "device",
@@ -76455,7 +76743,7 @@ Object.freeze({
76455
76743
  access: "create"
76456
76744
  }
76457
76745
  });
76458
- DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
76746
+ DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
76459
76747
  DeviceFeature.BatteryOperated;
76460
76748
  /** Reject after `ms`; always clears its own timer. */
76461
76749
  async function withTimeout$1(promise, ms, label) {
@@ -77497,6 +77785,71 @@ Object.freeze({
77497
77785
  form: "single",
77498
77786
  optional: false
77499
77787
  }],
77788
+ "dishwasher.getStatus": [{
77789
+ name: "deviceId",
77790
+ form: "single",
77791
+ optional: false
77792
+ }],
77793
+ "dishwasher.pause": [{
77794
+ name: "deviceId",
77795
+ form: "single",
77796
+ optional: false
77797
+ }],
77798
+ "dishwasher.setChildLock": [{
77799
+ name: "deviceId",
77800
+ form: "single",
77801
+ optional: false
77802
+ }],
77803
+ "dishwasher.setExtraDry": [{
77804
+ name: "deviceId",
77805
+ form: "single",
77806
+ optional: false
77807
+ }],
77808
+ "dishwasher.setHalfLoad": [{
77809
+ name: "deviceId",
77810
+ form: "single",
77811
+ optional: false
77812
+ }],
77813
+ "dishwasher.setHygienePlus": [{
77814
+ name: "deviceId",
77815
+ form: "single",
77816
+ optional: false
77817
+ }],
77818
+ "dishwasher.setIntensiveZone": [{
77819
+ name: "deviceId",
77820
+ form: "single",
77821
+ optional: false
77822
+ }],
77823
+ "dishwasher.setOption": [{
77824
+ name: "deviceId",
77825
+ form: "single",
77826
+ optional: false
77827
+ }],
77828
+ "dishwasher.setPower": [{
77829
+ name: "deviceId",
77830
+ form: "single",
77831
+ optional: false
77832
+ }],
77833
+ "dishwasher.setProgram": [{
77834
+ name: "deviceId",
77835
+ form: "single",
77836
+ optional: false
77837
+ }],
77838
+ "dishwasher.setVarioSpeedPlus": [{
77839
+ name: "deviceId",
77840
+ form: "single",
77841
+ optional: false
77842
+ }],
77843
+ "dishwasher.start": [{
77844
+ name: "deviceId",
77845
+ form: "single",
77846
+ optional: false
77847
+ }],
77848
+ "dishwasher.stop": [{
77849
+ name: "deviceId",
77850
+ form: "single",
77851
+ optional: false
77852
+ }],
77500
77853
  "doorbell.getStatus": [{
77501
77854
  name: "deviceId",
77502
77855
  form: "single",
@@ -77566,6 +77919,11 @@ Object.freeze({
77566
77919
  form: "single",
77567
77920
  optional: false
77568
77921
  }],
77922
+ "heatingValve.getStatus": [{
77923
+ name: "deviceId",
77924
+ form: "single",
77925
+ optional: false
77926
+ }],
77569
77927
  "humidifier.getStatus": [{
77570
77928
  name: "deviceId",
77571
77929
  form: "single",
@@ -103167,7 +103525,7 @@ var HikvisionProviderAddon = class extends BaseDeviceProvider {
103167
103525
  throw new Error(`Hikvision: ${reason}`);
103168
103526
  }
103169
103527
  async onInitialize() {
103170
- const regs = await super.onInitialize();
103528
+ const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
103171
103529
  regs.push({
103172
103530
  capability: failureContributionCapability,
103173
103531
  provider: { list: () => intercomFailureReport.list() }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-hikvision",
3
- "version": "1.2.152",
3
+ "version": "1.2.154",
4
4
  "description": "Hikvision camera device provider addon for CamStack — ISAPI over HTTP(S) with digest auth (snapshot, alarm stream, RTSP discovery)",
5
5
  "keywords": [
6
6
  "camstack",