@camstack/addon-provider-onvif 0.1.0 → 0.1.2
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/assets/icon.svg +5 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +81 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +28 -5
package/assets/icon.svg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#06b6d4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<circle cx="12" cy="12" r="10"/>
|
|
3
|
+
<circle cx="12" cy="12" r="6"/>
|
|
4
|
+
<circle cx="12" cy="12" r="2"/>
|
|
5
|
+
</svg>
|
package/dist/index.d.mts
CHANGED
|
@@ -147,12 +147,16 @@ declare class OnvifProvider implements IDeviceProvider {
|
|
|
147
147
|
readonly ctx: CamstackContext;
|
|
148
148
|
private devices;
|
|
149
149
|
private readonly clients;
|
|
150
|
+
private lastDiscoveredCameras;
|
|
150
151
|
constructor(config: OnvifProviderConfig, ctx: CamstackContext);
|
|
151
152
|
start(): Promise<void>;
|
|
152
153
|
private addCamera;
|
|
154
|
+
private loadAdoptedCameras;
|
|
153
155
|
stop(): Promise<void>;
|
|
154
156
|
getStatus(): ProviderStatus;
|
|
155
157
|
discoverDevices(): Promise<DiscoveredDevice[]>;
|
|
158
|
+
adoptDevice(externalId: string, config?: Record<string, unknown>): Promise<IDevice>;
|
|
159
|
+
private persistAdoptedCamera;
|
|
156
160
|
getDevices(): IDevice[];
|
|
157
161
|
getDeviceConfigSchema(): {
|
|
158
162
|
id: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -147,12 +147,16 @@ declare class OnvifProvider implements IDeviceProvider {
|
|
|
147
147
|
readonly ctx: CamstackContext;
|
|
148
148
|
private devices;
|
|
149
149
|
private readonly clients;
|
|
150
|
+
private lastDiscoveredCameras;
|
|
150
151
|
constructor(config: OnvifProviderConfig, ctx: CamstackContext);
|
|
151
152
|
start(): Promise<void>;
|
|
152
153
|
private addCamera;
|
|
154
|
+
private loadAdoptedCameras;
|
|
153
155
|
stop(): Promise<void>;
|
|
154
156
|
getStatus(): ProviderStatus;
|
|
155
157
|
discoverDevices(): Promise<DiscoveredDevice[]>;
|
|
158
|
+
adoptDevice(externalId: string, config?: Record<string, unknown>): Promise<IDevice>;
|
|
159
|
+
private persistAdoptedCamera;
|
|
156
160
|
getDevices(): IDevice[];
|
|
157
161
|
getDeviceConfigSchema(): {
|
|
158
162
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -195,6 +195,7 @@ var OnvifClient = class {
|
|
|
195
195
|
};
|
|
196
196
|
|
|
197
197
|
// src/onvif-device.ts
|
|
198
|
+
var import_types = require("@camstack/types");
|
|
198
199
|
var OnvifDevice = class {
|
|
199
200
|
constructor(client, config, ctx) {
|
|
200
201
|
this.client = client;
|
|
@@ -212,7 +213,7 @@ var OnvifDevice = class {
|
|
|
212
213
|
id;
|
|
213
214
|
name;
|
|
214
215
|
providerId;
|
|
215
|
-
type =
|
|
216
|
+
type = import_types.DeviceType.Camera;
|
|
216
217
|
capabilities;
|
|
217
218
|
ctx;
|
|
218
219
|
capabilityMap = /* @__PURE__ */ new Map();
|
|
@@ -454,6 +455,7 @@ var OnvifProvider = class {
|
|
|
454
455
|
ctx;
|
|
455
456
|
devices = [];
|
|
456
457
|
clients = /* @__PURE__ */ new Map();
|
|
458
|
+
lastDiscoveredCameras = [];
|
|
457
459
|
async start() {
|
|
458
460
|
if (this.config.discovery?.enabled !== false) {
|
|
459
461
|
const timeout = this.config.discovery?.timeout ?? 5e3;
|
|
@@ -474,6 +476,7 @@ var OnvifProvider = class {
|
|
|
474
476
|
for (const cam of this.config.cameras ?? []) {
|
|
475
477
|
await this.addCamera(cam);
|
|
476
478
|
}
|
|
479
|
+
await this.loadAdoptedCameras();
|
|
477
480
|
this.ctx.logger.info(
|
|
478
481
|
`ONVIF provider started with ${this.devices.length} camera(s)`
|
|
479
482
|
);
|
|
@@ -533,6 +536,26 @@ var OnvifProvider = class {
|
|
|
533
536
|
this.ctx.logger.warn(`Failed to connect to ${cam.host}: ${message}`);
|
|
534
537
|
}
|
|
535
538
|
}
|
|
539
|
+
async loadAdoptedCameras() {
|
|
540
|
+
const storage = this.ctx.storage;
|
|
541
|
+
if (!storage.structured) return;
|
|
542
|
+
try {
|
|
543
|
+
const records = await storage.structured.query("adopted-cameras", {});
|
|
544
|
+
for (const record of records) {
|
|
545
|
+
const cam = record.data;
|
|
546
|
+
const alreadyLoaded = this.devices.some(
|
|
547
|
+
(d) => d.id === `${this.id}/${cam.id}`
|
|
548
|
+
);
|
|
549
|
+
if (!alreadyLoaded) {
|
|
550
|
+
await this.addCamera(cam);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (records.length > 0) {
|
|
554
|
+
this.ctx.logger.info(`Restored ${records.length} adopted camera(s) from storage`);
|
|
555
|
+
}
|
|
556
|
+
} catch {
|
|
557
|
+
}
|
|
558
|
+
}
|
|
536
559
|
async stop() {
|
|
537
560
|
for (const client of this.clients.values()) {
|
|
538
561
|
client.disconnect();
|
|
@@ -546,6 +569,7 @@ var OnvifProvider = class {
|
|
|
546
569
|
}
|
|
547
570
|
async discoverDevices() {
|
|
548
571
|
const cameras = await discoverOnvifCameras();
|
|
572
|
+
this.lastDiscoveredCameras = cameras;
|
|
549
573
|
return cameras.map((c) => ({
|
|
550
574
|
externalId: c.host,
|
|
551
575
|
name: c.name ?? c.host,
|
|
@@ -554,6 +578,61 @@ var OnvifProvider = class {
|
|
|
554
578
|
metadata: { manufacturer: c.manufacturer, model: c.model }
|
|
555
579
|
}));
|
|
556
580
|
}
|
|
581
|
+
async adoptDevice(externalId, config) {
|
|
582
|
+
const existingDevice = this.devices.find(
|
|
583
|
+
(d) => d.id === `${this.id}/${externalId.replace(/\./g, "-")}`
|
|
584
|
+
);
|
|
585
|
+
if (existingDevice) {
|
|
586
|
+
return existingDevice;
|
|
587
|
+
}
|
|
588
|
+
let discovered = this.lastDiscoveredCameras.find((c) => c.host === externalId);
|
|
589
|
+
if (!discovered) {
|
|
590
|
+
this.ctx.logger.info(`Camera ${externalId} not in cache, re-discovering...`);
|
|
591
|
+
const cameras = await discoverOnvifCameras();
|
|
592
|
+
this.lastDiscoveredCameras = cameras;
|
|
593
|
+
discovered = cameras.find((c) => c.host === externalId);
|
|
594
|
+
}
|
|
595
|
+
if (!discovered) {
|
|
596
|
+
throw new Error(`Camera with externalId "${externalId}" not found on network`);
|
|
597
|
+
}
|
|
598
|
+
const cameraId = externalId.replace(/\./g, "-");
|
|
599
|
+
const cameraConfig = {
|
|
600
|
+
id: cameraId,
|
|
601
|
+
name: config?.["name"] ?? discovered.name ?? externalId,
|
|
602
|
+
host: discovered.host,
|
|
603
|
+
port: discovered.port,
|
|
604
|
+
username: config?.["username"] ?? this.config.defaultUsername,
|
|
605
|
+
password: config?.["password"] ?? this.config.defaultPassword
|
|
606
|
+
};
|
|
607
|
+
await this.addCamera(cameraConfig);
|
|
608
|
+
const device = this.devices.find((d) => d.id === `${this.id}/${cameraId}`);
|
|
609
|
+
if (!device) {
|
|
610
|
+
throw new Error(`Failed to create device for camera ${externalId}`);
|
|
611
|
+
}
|
|
612
|
+
await this.persistAdoptedCamera(cameraConfig);
|
|
613
|
+
this.ctx.logger.info(`Adopted camera ${cameraConfig.name} (${externalId})`);
|
|
614
|
+
return device;
|
|
615
|
+
}
|
|
616
|
+
async persistAdoptedCamera(cam) {
|
|
617
|
+
const storage = this.ctx.storage;
|
|
618
|
+
if (!storage.structured) return;
|
|
619
|
+
try {
|
|
620
|
+
const existing = await storage.structured.query("adopted-cameras", {
|
|
621
|
+
where: { id: cam.id },
|
|
622
|
+
limit: 1
|
|
623
|
+
});
|
|
624
|
+
if (existing.length === 0) {
|
|
625
|
+
await storage.structured.insert({
|
|
626
|
+
collection: "adopted-cameras",
|
|
627
|
+
id: cam.id,
|
|
628
|
+
data: { ...cam }
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
} catch (err) {
|
|
632
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
633
|
+
this.ctx.logger.warn(`Failed to persist adopted camera ${cam.id}: ${message}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
557
636
|
getDevices() {
|
|
558
637
|
return [...this.devices];
|
|
559
638
|
}
|
|
@@ -580,6 +659,7 @@ var OnvifProviderAddon = class {
|
|
|
580
659
|
id: "provider-onvif",
|
|
581
660
|
name: "ONVIF Camera Provider",
|
|
582
661
|
version: "0.1.0",
|
|
662
|
+
description: "Discovery automatica di camere ONVIF sulla rete locale",
|
|
583
663
|
capabilities: ["device-provider"]
|
|
584
664
|
};
|
|
585
665
|
provider = null;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/onvif-client.ts","../src/onvif-device.ts","../src/onvif-discovery.ts","../src/element-config-store.ts","../src/onvif-provider.ts","../src/addon.ts"],"sourcesContent":["export { OnvifProviderAddon } from './addon'\nexport { OnvifClient } from './onvif-client'\nexport { OnvifDevice } from './onvif-device'\nexport { OnvifProvider } from './onvif-provider'\nexport { discoverOnvifCameras } from './onvif-discovery'\nexport type {\n OnvifProviderConfig,\n OnvifCameraConfig,\n DiscoveredOnvifCamera,\n} from './onvif-types'\n","import { Cam } from 'onvif'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport class OnvifClient {\n private cam: InstanceType<typeof Cam> | null = null\n\n constructor(\n private readonly host: string,\n private readonly port: number,\n private readonly username: string,\n private readonly password: string,\n private readonly logger: IScopedLogger,\n ) {}\n\n /** Connect to the camera */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.cam = new Cam(\n {\n hostname: this.host,\n port: this.port,\n username: this.username,\n password: this.password,\n },\n (err: Error | null) => {\n if (err) {\n reject(err)\n } else {\n this.logger.info(`Connected to ONVIF camera at ${this.host}:${this.port}`)\n resolve()\n }\n },\n )\n })\n }\n\n /** Get device info */\n async getDeviceInfo(): Promise<{\n manufacturer: string\n model: string\n firmwareVersion: string\n serialNumber: string\n }> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getDeviceInformation((err: Error | null, info: any) => {\n if (err) reject(err)\n else resolve(info)\n })\n })\n }\n\n /** Get RTSP stream URI */\n async getStreamUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = { protocol: 'RTSP' }\n if (profileToken) options.profileToken = profileToken\n this.cam.getStreamUri(options, (err: Error | null, stream: any) => {\n if (err) reject(err)\n else resolve(stream.uri)\n })\n })\n }\n\n /** Get available media profiles */\n async getProfiles(): Promise<\n Array<{ token: string; name: string; videoWidth?: number; videoHeight?: number }>\n > {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getProfiles((err: Error | null, profiles: any[]) => {\n if (err) reject(err)\n else\n resolve(\n profiles.map((p: any) => ({\n token: p.$.token ?? p.token,\n name: p.name,\n videoWidth: p.videoEncoderConfiguration?.resolution?.width,\n videoHeight: p.videoEncoderConfiguration?.resolution?.height,\n })),\n )\n })\n })\n }\n\n /** Get snapshot URI */\n async getSnapshotUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = {}\n if (profileToken) options.profileToken = profileToken\n this.cam.getSnapshotUri(options, (err: Error | null, res: any) => {\n if (err) reject(err)\n else resolve(res.uri)\n })\n })\n }\n\n /** Check if PTZ is supported */\n hasPtz(): boolean {\n return (this.cam as any)?.ptzUri != null\n }\n\n /** PTZ move (continuous) */\n async ptzMove(options: {\n x?: number\n y?: number\n zoom?: number\n speed?: number\n }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.continuousMove(\n {\n x: options.x ?? 0,\n y: options.y ?? 0,\n zoom: options.zoom ?? 0,\n timeout: 1000,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** PTZ stop */\n async ptzStop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.stop({}, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n /** PTZ absolute move */\n async ptzAbsoluteMove(options: { x: number; y: number; zoom: number }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.absoluteMove(\n {\n x: options.x,\n y: options.y,\n zoom: options.zoom,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** Get PTZ presets */\n async getPtzPresets(): Promise<Array<{ token: string; name: string }>> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getPresets({}, (err: Error | null, presets: any) => {\n if (err) reject(err)\n else {\n const list = Array.isArray(presets) ? presets : [presets]\n resolve(\n list.filter(Boolean).map((p: any) => ({\n token: p.$.token ?? String(p.token),\n name: p.name ?? p.$.token ?? 'Preset',\n })),\n )\n }\n })\n })\n }\n\n /** Go to PTZ preset */\n async gotoPreset(presetToken: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.gotoPreset({ preset: presetToken }, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n disconnect(): void {\n this.cam = null\n }\n}\n","import type {\n IDevice,\n DeviceType,\n DeviceState,\n DeviceMetadata,\n DeviceCapabilityName,\n IDeviceCapability,\n CamstackContext,\n ICamera,\n StreamOption,\n ConnectionMode,\n IPanTiltZoom,\n} from '@camstack/types'\nimport type { OnvifClient } from './onvif-client'\n\nexport interface OnvifDeviceConfig {\n readonly cameraId: string\n readonly cameraName: string\n readonly providerId: string\n readonly rtspUrl: string\n readonly subStreamUrl?: string\n readonly snapshotUrl?: string\n readonly hasPtz: boolean\n readonly profiles: ReadonlyArray<{\n token: string\n name: string\n videoWidth?: number\n videoHeight?: number\n }>\n readonly manufacturer?: string\n readonly model?: string\n readonly firmware?: string\n}\n\nexport class OnvifDevice implements IDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly type: DeviceType = 'camera'\n readonly capabilities: DeviceCapabilityName[]\n readonly ctx: CamstackContext\n\n private readonly capabilityMap = new Map<DeviceCapabilityName, IDeviceCapability>()\n\n constructor(\n private readonly client: OnvifClient,\n private readonly config: OnvifDeviceConfig,\n ctx: CamstackContext,\n ) {\n this.id = `${config.providerId}/${config.cameraId}`\n this.name = config.cameraName\n this.providerId = config.providerId\n this.ctx = ctx\n\n const caps: DeviceCapabilityName[] = ['camera']\n if (config.hasPtz) caps.push('panTiltZoom')\n this.capabilities = caps\n\n this.capabilityMap.set('camera', this.createCamera())\n if (config.hasPtz) this.capabilityMap.set('panTiltZoom', this.createPtz())\n }\n\n getCapability<T extends IDeviceCapability>(cap: DeviceCapabilityName): T | null {\n return (this.capabilityMap.get(cap) as T) ?? null\n }\n\n hasCapability(cap: DeviceCapabilityName): boolean {\n return this.capabilityMap.has(cap)\n }\n\n getState(): DeviceState {\n return { online: true }\n }\n\n getMetadata(): DeviceMetadata {\n return {\n manufacturer: this.config.manufacturer ?? 'ONVIF',\n model: this.config.model,\n firmware: this.config.firmware,\n }\n }\n\n private createCamera(): ICamera {\n const { config } = this\n return {\n kind: 'camera',\n\n async getSnapshot() {\n if (config.snapshotUrl) {\n const res = await fetch(config.snapshotUrl)\n return Buffer.from(await res.arrayBuffer())\n }\n return Buffer.alloc(0)\n },\n\n async getStreamOptions(): Promise<StreamOption[]> {\n const options: StreamOption[] = [\n {\n id: `${config.cameraId}_main`,\n label: 'Main',\n protocol: 'rtsp',\n quality: 'main',\n url: config.rtspUrl,\n },\n ]\n if (config.subStreamUrl) {\n options.push({\n id: `${config.cameraId}_sub`,\n label: 'Sub',\n protocol: 'rtsp',\n quality: 'sub',\n url: config.subStreamUrl,\n })\n }\n return options\n },\n\n async getStreamUrl(option: StreamOption) {\n return option.url ?? config.rtspUrl\n },\n\n getConnectionMode(): ConnectionMode {\n return 'on-demand'\n },\n\n async setConnectionMode() {},\n }\n }\n\n private createPtz(): IPanTiltZoom {\n const { client } = this\n return {\n kind: 'panTiltZoom',\n\n async move(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom, speed: cmd.speed })\n },\n\n async continuousMove(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom })\n },\n\n async stop() {\n await client.ptzStop()\n },\n\n async getPresets() {\n const presets = await client.getPtzPresets()\n return presets.map((p) => ({ id: p.token, name: p.name }))\n },\n\n async goToPreset(presetId: string) {\n await client.gotoPreset(presetId)\n },\n\n async goHome() {\n await client.ptzAbsoluteMove({ x: 0, y: 0, zoom: 0 })\n },\n\n async getPosition() {\n return { pan: 0, tilt: 0, zoom: 0 }\n },\n }\n }\n}\n","import { Discovery } from 'onvif'\nimport type { DiscoveredOnvifCamera } from './onvif-types'\n\n/**\n * Discovers ONVIF cameras on the local network via WS-Discovery.\n * Returns a list of found cameras after the given timeout.\n */\nexport async function discoverOnvifCameras(\n timeout: number = 5000,\n): Promise<readonly DiscoveredOnvifCamera[]> {\n return new Promise((resolve) => {\n const cameras: DiscoveredOnvifCamera[] = []\n\n Discovery.on('device', (cam: any) => {\n cameras.push({\n host: cam.hostname,\n port: cam.port ?? 80,\n name: cam.name,\n manufacturer: cam.manufacturer,\n model: cam.model,\n scopes: cam.scopes,\n })\n })\n\n Discovery.probe({ timeout })\n\n setTimeout(() => {\n Discovery.removeAllListeners('device')\n resolve(cameras)\n }, timeout + 500)\n })\n}\n","import type { IElementConfig } from '@camstack/types'\nimport type { IStorageLocation } from '@camstack/types'\n\n/**\n * Persisted config store for a single element.\n * Reads/writes to the element's scoped storage under the 'config' collection.\n * Notifies listeners on every change.\n */\nexport class ElementConfigStore implements IElementConfig {\n private cache: Record<string, unknown> = {}\n private listeners: Set<(config: Record<string, unknown>) => void> = new Set()\n private loaded = false\n\n constructor(\n private readonly elementId: string,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Load config from storage into cache. Called once on first access. */\n private async ensureLoaded(): Promise<void> {\n if (this.loaded) return\n if (!this.storage.structured) {\n this.loaded = true\n return\n }\n\n try {\n const records = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n if (records.length > 0) {\n this.cache = (records[0] as any).data ?? {}\n }\n } catch {\n // Storage might not be ready yet\n }\n this.loaded = true\n }\n\n getAll(): Record<string, unknown> {\n return { ...this.cache }\n }\n\n get<T = unknown>(key: string): T | undefined {\n const parts = key.split('.')\n let current: unknown = this.cache\n for (const part of parts) {\n if (current == null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[part]\n }\n return current as T | undefined\n }\n\n async set(key: string, value: unknown): Promise<void> {\n await this.ensureLoaded()\n setNestedValue(this.cache, key, value)\n await this.persist()\n this.notifyListeners()\n }\n\n async setAll(config: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n this.cache = { ...config }\n await this.persist()\n this.notifyListeners()\n }\n\n onChange(callback: (config: Record<string, unknown>) => void): () => void {\n this.listeners.add(callback)\n return () => { this.listeners.delete(callback) }\n }\n\n /** Initialize from storage — called by ContextFactory after creation */\n async load(): Promise<void> {\n await this.ensureLoaded()\n }\n\n /** Initialize with default values (doesn't overwrite existing) */\n async loadDefaults(defaults: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n if (Object.keys(this.cache).length === 0) {\n this.cache = { ...defaults }\n await this.persist()\n }\n }\n\n private async persist(): Promise<void> {\n if (!this.storage.structured) return\n\n try {\n const existing = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n\n if (existing.length > 0) {\n await this.storage.structured.update('config', this.elementId, this.cache)\n } else {\n await this.storage.structured.insert({\n collection: 'config',\n id: this.elementId,\n data: this.cache,\n })\n }\n } catch {\n // Storage might not be ready\n }\n }\n\n private notifyListeners(): void {\n const snapshot = this.getAll()\n for (const listener of this.listeners) {\n try {\n listener(snapshot)\n } catch {\n // Don't let one bad listener kill others\n }\n }\n }\n}\n\nfunction setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split('.')\n let current: Record<string, unknown> = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n current[parts[parts.length - 1]!] = value\n}\n","import { OnvifClient } from './onvif-client'\nimport { OnvifDevice } from './onvif-device'\nimport { discoverOnvifCameras } from './onvif-discovery'\nimport { ElementConfigStore } from './element-config-store'\nimport type {\n IDeviceProvider,\n ProviderStatus,\n DiscoveredDevice,\n LiveEvent,\n IDevice,\n DeviceType,\n DeviceCapabilityName,\n CamstackContext,\n} from '@camstack/types'\nimport type { OnvifProviderConfig, OnvifCameraConfig } from './onvif-types'\n\nexport class OnvifProvider implements IDeviceProvider {\n readonly id: string\n readonly type = 'onvif'\n readonly name: string\n readonly discoveryMode: 'both' = 'both'\n readonly ctx: CamstackContext\n\n private devices: OnvifDevice[] = []\n private readonly clients: Map<string, OnvifClient> = new Map()\n\n constructor(\n private readonly config: OnvifProviderConfig,\n ctx: CamstackContext,\n ) {\n this.id = config.id\n this.name = config.name\n this.ctx = ctx\n }\n\n async start(): Promise<void> {\n // 1. Auto-discover cameras on LAN (if enabled)\n if (this.config.discovery?.enabled !== false) {\n const timeout = this.config.discovery?.timeout ?? 5000\n this.ctx.logger.info(`Starting ONVIF discovery (timeout: ${timeout}ms)`)\n\n const discovered = await discoverOnvifCameras(timeout)\n this.ctx.logger.info(`Discovered ${discovered.length} ONVIF camera(s)`)\n\n for (const cam of discovered) {\n await this.addCamera({\n id: cam.host.replace(/\\./g, '-'),\n name: cam.name ?? cam.host,\n host: cam.host,\n port: cam.port,\n username: this.config.defaultUsername,\n password: this.config.defaultPassword,\n })\n }\n }\n\n // 2. Add manually configured cameras\n for (const cam of this.config.cameras ?? []) {\n await this.addCamera(cam)\n }\n\n this.ctx.logger.info(\n `ONVIF provider started with ${this.devices.length} camera(s)`,\n )\n }\n\n private async addCamera(cam: OnvifCameraConfig): Promise<void> {\n try {\n const client = new OnvifClient(\n cam.host,\n cam.port ?? 80,\n cam.username ?? '',\n cam.password ?? '',\n this.ctx.logger.child(cam.name),\n )\n await client.connect()\n\n const info = await client.getDeviceInfo()\n const profiles = await client.getProfiles()\n const mainProfile = profiles[0]\n const subProfile = profiles.length > 1 ? profiles[1] : undefined\n\n const rtspUrl = cam.rtspUrl ?? (await client.getStreamUri(mainProfile?.token))\n const subStreamUrl = subProfile\n ? await client.getStreamUri(subProfile.token)\n : undefined\n\n let snapshotUrl: string | undefined\n try {\n snapshotUrl = await client.getSnapshotUri(mainProfile?.token)\n } catch {\n // Snapshot not supported by this camera\n }\n\n const deviceCtx: CamstackContext = {\n id: `device:${this.id}/${cam.id}`,\n logger: this.ctx.logger.child(cam.name),\n eventBus: this.ctx.eventBus,\n storage: this.ctx.storage,\n config: new ElementConfigStore(`device:${this.id}/${cam.id}`, this.ctx.storage),\n }\n\n const device = new OnvifDevice(\n client,\n {\n cameraId: cam.id,\n cameraName: cam.name,\n providerId: this.id,\n rtspUrl,\n subStreamUrl,\n snapshotUrl,\n hasPtz: client.hasPtz(),\n profiles,\n manufacturer: info.manufacturer,\n model: info.model,\n firmware: info.firmwareVersion,\n },\n deviceCtx,\n )\n\n this.devices = [...this.devices, device]\n this.clients.set(cam.id, client)\n this.ctx.logger.info(\n `Camera ${cam.name} (${cam.host}) connected — PTZ: ${client.hasPtz()}, profiles: ${profiles.length}`,\n )\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn(`Failed to connect to ${cam.host}: ${message}`)\n }\n }\n\n async stop(): Promise<void> {\n for (const client of this.clients.values()) {\n client.disconnect()\n }\n this.devices = []\n this.clients.clear()\n this.ctx.logger.info('ONVIF provider stopped')\n }\n\n getStatus(): ProviderStatus {\n return { connected: true, deviceCount: this.devices.length }\n }\n\n async discoverDevices(): Promise<DiscoveredDevice[]> {\n const cameras = await discoverOnvifCameras()\n return cameras.map((c) => ({\n externalId: c.host,\n name: c.name ?? c.host,\n type: 'camera' as DeviceType,\n capabilities: ['camera'] as DeviceCapabilityName[],\n metadata: { manufacturer: c.manufacturer, model: c.model },\n }))\n }\n\n getDevices(): IDevice[] {\n return [...this.devices]\n }\n\n getDeviceConfigSchema() {\n return {\n id: 'string',\n name: 'string',\n host: 'string (IP or hostname)',\n port: 'number (default: 80)',\n username: 'string (optional)',\n password: 'string (optional)',\n rtspUrl: 'string (optional, override ONVIF stream URI)',\n }\n }\n\n subscribeLiveEvents(_callback: (event: LiveEvent) => void): () => void {\n // ONVIF events via pipeline — no native event subscription here\n return () => {}\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n CapabilityProviderMap,\n ConfigUISchema,\n IConfigurable,\n} from '@camstack/types'\nimport { OnvifProvider } from './onvif-provider'\nimport type { OnvifProviderConfig } from './onvif-types'\n\nexport class OnvifProviderAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'provider-onvif',\n name: 'ONVIF Camera Provider',\n version: '0.1.0',\n capabilities: ['device-provider'],\n }\n\n private provider: OnvifProvider | null = null\n\n async initialize(context: AddonContext): Promise<void> {\n const config = context.addonConfig as unknown as OnvifProviderConfig\n\n const providerConfig: OnvifProviderConfig = {\n id: config.id ?? 'onvif-default',\n name: config.name ?? 'ONVIF Cameras',\n discovery: config.discovery,\n cameras: config.cameras,\n defaultUsername: config.defaultUsername,\n defaultPassword: config.defaultPassword,\n }\n\n this.provider = new OnvifProvider(providerConfig, {\n id: context.id,\n logger: context.logger,\n eventBus: context.eventBus,\n storage: context.storage,\n config: context.config,\n })\n\n context.logger.info('ONVIF provider addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.provider?.stop()\n this.provider = null\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'device-provider' && this.provider) {\n return this.provider as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'discovery',\n title: 'ONVIF Discovery',\n description: 'Auto-discover ONVIF cameras on the local network',\n columns: 2,\n fields: [\n { type: 'boolean', key: 'discovery.enabled', label: 'Enable Auto-Discovery' },\n { type: 'number', key: 'discovery.timeout', label: 'Discovery Timeout', unit: 'ms', min: 1000, max: 30000, step: 1000 },\n ],\n },\n {\n id: 'credentials',\n title: 'Default Credentials',\n description: 'Default credentials for discovered cameras',\n columns: 2,\n fields: [\n { type: 'text', key: 'defaultUsername', label: 'Default Username' },\n { type: 'password', key: 'defaultPassword', label: 'Default Password', showToggle: true },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return {}\n }\n\n async onConfigChange(_config: Record<string, unknown>): Promise<void> {\n // Restart provider with new config\n }\n}\n"],"mappings":"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","names":["import_onvif"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/onvif-client.ts","../src/onvif-device.ts","../src/onvif-discovery.ts","../src/element-config-store.ts","../src/onvif-provider.ts","../src/addon.ts"],"sourcesContent":["export { OnvifProviderAddon } from './addon'\nexport { OnvifClient } from './onvif-client'\nexport { OnvifDevice } from './onvif-device'\nexport { OnvifProvider } from './onvif-provider'\nexport { discoverOnvifCameras } from './onvif-discovery'\nexport type {\n OnvifProviderConfig,\n OnvifCameraConfig,\n DiscoveredOnvifCamera,\n} from './onvif-types'\n","import { Cam } from 'onvif'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport class OnvifClient {\n private cam: InstanceType<typeof Cam> | null = null\n\n constructor(\n private readonly host: string,\n private readonly port: number,\n private readonly username: string,\n private readonly password: string,\n private readonly logger: IScopedLogger,\n ) {}\n\n /** Connect to the camera */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.cam = new Cam(\n {\n hostname: this.host,\n port: this.port,\n username: this.username,\n password: this.password,\n },\n (err: Error | null) => {\n if (err) {\n reject(err)\n } else {\n this.logger.info(`Connected to ONVIF camera at ${this.host}:${this.port}`)\n resolve()\n }\n },\n )\n })\n }\n\n /** Get device info */\n async getDeviceInfo(): Promise<{\n manufacturer: string\n model: string\n firmwareVersion: string\n serialNumber: string\n }> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getDeviceInformation((err: Error | null, info: any) => {\n if (err) reject(err)\n else resolve(info)\n })\n })\n }\n\n /** Get RTSP stream URI */\n async getStreamUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = { protocol: 'RTSP' }\n if (profileToken) options.profileToken = profileToken\n this.cam.getStreamUri(options, (err: Error | null, stream: any) => {\n if (err) reject(err)\n else resolve(stream.uri)\n })\n })\n }\n\n /** Get available media profiles */\n async getProfiles(): Promise<\n Array<{ token: string; name: string; videoWidth?: number; videoHeight?: number }>\n > {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getProfiles((err: Error | null, profiles: any[]) => {\n if (err) reject(err)\n else\n resolve(\n profiles.map((p: any) => ({\n token: p.$.token ?? p.token,\n name: p.name,\n videoWidth: p.videoEncoderConfiguration?.resolution?.width,\n videoHeight: p.videoEncoderConfiguration?.resolution?.height,\n })),\n )\n })\n })\n }\n\n /** Get snapshot URI */\n async getSnapshotUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = {}\n if (profileToken) options.profileToken = profileToken\n this.cam.getSnapshotUri(options, (err: Error | null, res: any) => {\n if (err) reject(err)\n else resolve(res.uri)\n })\n })\n }\n\n /** Check if PTZ is supported */\n hasPtz(): boolean {\n return (this.cam as any)?.ptzUri != null\n }\n\n /** PTZ move (continuous) */\n async ptzMove(options: {\n x?: number\n y?: number\n zoom?: number\n speed?: number\n }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.continuousMove(\n {\n x: options.x ?? 0,\n y: options.y ?? 0,\n zoom: options.zoom ?? 0,\n timeout: 1000,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** PTZ stop */\n async ptzStop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.stop({}, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n /** PTZ absolute move */\n async ptzAbsoluteMove(options: { x: number; y: number; zoom: number }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.absoluteMove(\n {\n x: options.x,\n y: options.y,\n zoom: options.zoom,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** Get PTZ presets */\n async getPtzPresets(): Promise<Array<{ token: string; name: string }>> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getPresets({}, (err: Error | null, presets: any) => {\n if (err) reject(err)\n else {\n const list = Array.isArray(presets) ? presets : [presets]\n resolve(\n list.filter(Boolean).map((p: any) => ({\n token: p.$.token ?? String(p.token),\n name: p.name ?? p.$.token ?? 'Preset',\n })),\n )\n }\n })\n })\n }\n\n /** Go to PTZ preset */\n async gotoPreset(presetToken: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.gotoPreset({ preset: presetToken }, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n disconnect(): void {\n this.cam = null\n }\n}\n","import { DeviceType } from '@camstack/types'\nimport type {\n IDevice,\n DeviceState,\n DeviceMetadata,\n DeviceCapabilityName,\n IDeviceCapability,\n CamstackContext,\n ICamera,\n StreamOption,\n ConnectionMode,\n IPanTiltZoom,\n} from '@camstack/types'\nimport type { OnvifClient } from './onvif-client'\n\nexport interface OnvifDeviceConfig {\n readonly cameraId: string\n readonly cameraName: string\n readonly providerId: string\n readonly rtspUrl: string\n readonly subStreamUrl?: string\n readonly snapshotUrl?: string\n readonly hasPtz: boolean\n readonly profiles: ReadonlyArray<{\n token: string\n name: string\n videoWidth?: number\n videoHeight?: number\n }>\n readonly manufacturer?: string\n readonly model?: string\n readonly firmware?: string\n}\n\nexport class OnvifDevice implements IDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly type: DeviceType = DeviceType.Camera\n readonly capabilities: DeviceCapabilityName[]\n readonly ctx: CamstackContext\n\n private readonly capabilityMap = new Map<DeviceCapabilityName, IDeviceCapability>()\n\n constructor(\n private readonly client: OnvifClient,\n private readonly config: OnvifDeviceConfig,\n ctx: CamstackContext,\n ) {\n this.id = `${config.providerId}/${config.cameraId}`\n this.name = config.cameraName\n this.providerId = config.providerId\n this.ctx = ctx\n\n const caps: DeviceCapabilityName[] = ['camera']\n if (config.hasPtz) caps.push('panTiltZoom')\n this.capabilities = caps\n\n this.capabilityMap.set('camera', this.createCamera())\n if (config.hasPtz) this.capabilityMap.set('panTiltZoom', this.createPtz())\n }\n\n getCapability<T extends IDeviceCapability>(cap: DeviceCapabilityName): T | null {\n return (this.capabilityMap.get(cap) as T) ?? null\n }\n\n hasCapability(cap: DeviceCapabilityName): boolean {\n return this.capabilityMap.has(cap)\n }\n\n getState(): DeviceState {\n return { online: true }\n }\n\n getMetadata(): DeviceMetadata {\n return {\n manufacturer: this.config.manufacturer ?? 'ONVIF',\n model: this.config.model,\n firmware: this.config.firmware,\n }\n }\n\n private createCamera(): ICamera {\n const { config } = this\n return {\n kind: 'camera',\n\n async getSnapshot() {\n if (config.snapshotUrl) {\n const res = await fetch(config.snapshotUrl)\n return Buffer.from(await res.arrayBuffer())\n }\n return Buffer.alloc(0)\n },\n\n async getStreamOptions(): Promise<StreamOption[]> {\n const options: StreamOption[] = [\n {\n id: `${config.cameraId}_main`,\n label: 'Main',\n protocol: 'rtsp',\n quality: 'main',\n url: config.rtspUrl,\n },\n ]\n if (config.subStreamUrl) {\n options.push({\n id: `${config.cameraId}_sub`,\n label: 'Sub',\n protocol: 'rtsp',\n quality: 'sub',\n url: config.subStreamUrl,\n })\n }\n return options\n },\n\n async getStreamUrl(option: StreamOption) {\n return option.url ?? config.rtspUrl\n },\n\n getConnectionMode(): ConnectionMode {\n return 'on-demand'\n },\n\n async setConnectionMode() {},\n }\n }\n\n private createPtz(): IPanTiltZoom {\n const { client } = this\n return {\n kind: 'panTiltZoom',\n\n async move(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom, speed: cmd.speed })\n },\n\n async continuousMove(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom })\n },\n\n async stop() {\n await client.ptzStop()\n },\n\n async getPresets() {\n const presets = await client.getPtzPresets()\n return presets.map((p) => ({ id: p.token, name: p.name }))\n },\n\n async goToPreset(presetId: string) {\n await client.gotoPreset(presetId)\n },\n\n async goHome() {\n await client.ptzAbsoluteMove({ x: 0, y: 0, zoom: 0 })\n },\n\n async getPosition() {\n return { pan: 0, tilt: 0, zoom: 0 }\n },\n }\n }\n}\n","import { Discovery } from 'onvif'\nimport type { DiscoveredOnvifCamera } from './onvif-types'\n\n/**\n * Discovers ONVIF cameras on the local network via WS-Discovery.\n * Returns a list of found cameras after the given timeout.\n */\nexport async function discoverOnvifCameras(\n timeout: number = 5000,\n): Promise<readonly DiscoveredOnvifCamera[]> {\n return new Promise((resolve) => {\n const cameras: DiscoveredOnvifCamera[] = []\n\n Discovery.on('device', (cam: any) => {\n cameras.push({\n host: cam.hostname,\n port: cam.port ?? 80,\n name: cam.name,\n manufacturer: cam.manufacturer,\n model: cam.model,\n scopes: cam.scopes,\n })\n })\n\n Discovery.probe({ timeout })\n\n setTimeout(() => {\n Discovery.removeAllListeners('device')\n resolve(cameras)\n }, timeout + 500)\n })\n}\n","import type { IElementConfig } from '@camstack/types'\nimport type { IStorageLocation } from '@camstack/types'\n\n/**\n * Persisted config store for a single element.\n * Reads/writes to the element's scoped storage under the 'config' collection.\n * Notifies listeners on every change.\n */\nexport class ElementConfigStore implements IElementConfig {\n private cache: Record<string, unknown> = {}\n private listeners: Set<(config: Record<string, unknown>) => void> = new Set()\n private loaded = false\n\n constructor(\n private readonly elementId: string,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Load config from storage into cache. Called once on first access. */\n private async ensureLoaded(): Promise<void> {\n if (this.loaded) return\n if (!this.storage.structured) {\n this.loaded = true\n return\n }\n\n try {\n const records = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n if (records.length > 0) {\n this.cache = (records[0] as any).data ?? {}\n }\n } catch {\n // Storage might not be ready yet\n }\n this.loaded = true\n }\n\n getAll(): Record<string, unknown> {\n return { ...this.cache }\n }\n\n get<T = unknown>(key: string): T | undefined {\n const parts = key.split('.')\n let current: unknown = this.cache\n for (const part of parts) {\n if (current == null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[part]\n }\n return current as T | undefined\n }\n\n async set(key: string, value: unknown): Promise<void> {\n await this.ensureLoaded()\n setNestedValue(this.cache, key, value)\n await this.persist()\n this.notifyListeners()\n }\n\n async setAll(config: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n this.cache = { ...config }\n await this.persist()\n this.notifyListeners()\n }\n\n onChange(callback: (config: Record<string, unknown>) => void): () => void {\n this.listeners.add(callback)\n return () => { this.listeners.delete(callback) }\n }\n\n /** Initialize from storage — called by ContextFactory after creation */\n async load(): Promise<void> {\n await this.ensureLoaded()\n }\n\n /** Initialize with default values (doesn't overwrite existing) */\n async loadDefaults(defaults: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n if (Object.keys(this.cache).length === 0) {\n this.cache = { ...defaults }\n await this.persist()\n }\n }\n\n private async persist(): Promise<void> {\n if (!this.storage.structured) return\n\n try {\n const existing = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n\n if (existing.length > 0) {\n await this.storage.structured.update('config', this.elementId, this.cache)\n } else {\n await this.storage.structured.insert({\n collection: 'config',\n id: this.elementId,\n data: this.cache,\n })\n }\n } catch {\n // Storage might not be ready\n }\n }\n\n private notifyListeners(): void {\n const snapshot = this.getAll()\n for (const listener of this.listeners) {\n try {\n listener(snapshot)\n } catch {\n // Don't let one bad listener kill others\n }\n }\n }\n}\n\nfunction setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split('.')\n let current: Record<string, unknown> = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n current[parts[parts.length - 1]!] = value\n}\n","import { OnvifClient } from './onvif-client'\nimport { OnvifDevice } from './onvif-device'\nimport { discoverOnvifCameras } from './onvif-discovery'\nimport { ElementConfigStore } from './element-config-store'\nimport type {\n IDeviceProvider,\n ProviderStatus,\n DiscoveredDevice,\n LiveEvent,\n IDevice,\n DeviceType,\n DeviceCapabilityName,\n CamstackContext,\n} from '@camstack/types'\nimport type { OnvifProviderConfig, OnvifCameraConfig, DiscoveredOnvifCamera } from './onvif-types'\n\nexport class OnvifProvider implements IDeviceProvider {\n readonly id: string\n readonly type = 'onvif'\n readonly name: string\n readonly discoveryMode: 'both' = 'both'\n readonly ctx: CamstackContext\n\n private devices: OnvifDevice[] = []\n private readonly clients: Map<string, OnvifClient> = new Map()\n private lastDiscoveredCameras: readonly DiscoveredOnvifCamera[] = []\n\n constructor(\n private readonly config: OnvifProviderConfig,\n ctx: CamstackContext,\n ) {\n this.id = config.id\n this.name = config.name\n this.ctx = ctx\n }\n\n async start(): Promise<void> {\n // 1. Auto-discover cameras on LAN (if enabled)\n if (this.config.discovery?.enabled !== false) {\n const timeout = this.config.discovery?.timeout ?? 5000\n this.ctx.logger.info(`Starting ONVIF discovery (timeout: ${timeout}ms)`)\n\n const discovered = await discoverOnvifCameras(timeout)\n this.ctx.logger.info(`Discovered ${discovered.length} ONVIF camera(s)`)\n\n for (const cam of discovered) {\n await this.addCamera({\n id: cam.host.replace(/\\./g, '-'),\n name: cam.name ?? cam.host,\n host: cam.host,\n port: cam.port,\n username: this.config.defaultUsername,\n password: this.config.defaultPassword,\n })\n }\n }\n\n // 2. Add manually configured cameras\n for (const cam of this.config.cameras ?? []) {\n await this.addCamera(cam)\n }\n\n // 3. Restore previously adopted cameras from storage\n await this.loadAdoptedCameras()\n\n this.ctx.logger.info(\n `ONVIF provider started with ${this.devices.length} camera(s)`,\n )\n }\n\n private async addCamera(cam: OnvifCameraConfig): Promise<void> {\n try {\n const client = new OnvifClient(\n cam.host,\n cam.port ?? 80,\n cam.username ?? '',\n cam.password ?? '',\n this.ctx.logger.child(cam.name),\n )\n await client.connect()\n\n const info = await client.getDeviceInfo()\n const profiles = await client.getProfiles()\n const mainProfile = profiles[0]\n const subProfile = profiles.length > 1 ? profiles[1] : undefined\n\n const rtspUrl = cam.rtspUrl ?? (await client.getStreamUri(mainProfile?.token))\n const subStreamUrl = subProfile\n ? await client.getStreamUri(subProfile.token)\n : undefined\n\n let snapshotUrl: string | undefined\n try {\n snapshotUrl = await client.getSnapshotUri(mainProfile?.token)\n } catch {\n // Snapshot not supported by this camera\n }\n\n const deviceCtx: CamstackContext = {\n id: `device:${this.id}/${cam.id}`,\n logger: this.ctx.logger.child(cam.name),\n eventBus: this.ctx.eventBus,\n storage: this.ctx.storage,\n config: new ElementConfigStore(`device:${this.id}/${cam.id}`, this.ctx.storage),\n }\n\n const device = new OnvifDevice(\n client,\n {\n cameraId: cam.id,\n cameraName: cam.name,\n providerId: this.id,\n rtspUrl,\n subStreamUrl,\n snapshotUrl,\n hasPtz: client.hasPtz(),\n profiles,\n manufacturer: info.manufacturer,\n model: info.model,\n firmware: info.firmwareVersion,\n },\n deviceCtx,\n )\n\n this.devices = [...this.devices, device]\n this.clients.set(cam.id, client)\n this.ctx.logger.info(\n `Camera ${cam.name} (${cam.host}) connected — PTZ: ${client.hasPtz()}, profiles: ${profiles.length}`,\n )\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn(`Failed to connect to ${cam.host}: ${message}`)\n }\n }\n\n private async loadAdoptedCameras(): Promise<void> {\n const storage = this.ctx.storage\n if (!storage.structured) return\n\n try {\n const records = await storage.structured.query('adopted-cameras', {})\n for (const record of records) {\n const cam = (record as any).data as OnvifCameraConfig\n // Skip if already loaded (e.g. matched by manual config or discovery)\n const alreadyLoaded = this.devices.some(\n (d) => d.id === `${this.id}/${cam.id}`,\n )\n if (!alreadyLoaded) {\n await this.addCamera(cam)\n }\n }\n if (records.length > 0) {\n this.ctx.logger.info(`Restored ${records.length} adopted camera(s) from storage`)\n }\n } catch {\n // Storage might not be ready yet\n }\n }\n\n async stop(): Promise<void> {\n for (const client of this.clients.values()) {\n client.disconnect()\n }\n this.devices = []\n this.clients.clear()\n this.ctx.logger.info('ONVIF provider stopped')\n }\n\n getStatus(): ProviderStatus {\n return { connected: true, deviceCount: this.devices.length }\n }\n\n async discoverDevices(): Promise<DiscoveredDevice[]> {\n const cameras = await discoverOnvifCameras()\n this.lastDiscoveredCameras = cameras\n return cameras.map((c) => ({\n externalId: c.host,\n name: c.name ?? c.host,\n type: 'camera' as DeviceType,\n capabilities: ['camera'] as DeviceCapabilityName[],\n metadata: { manufacturer: c.manufacturer, model: c.model },\n }))\n }\n\n async adoptDevice(externalId: string, config?: Record<string, unknown>): Promise<IDevice> {\n // Check if already adopted\n const existingDevice = this.devices.find(\n (d) => d.id === `${this.id}/${externalId.replace(/\\./g, '-')}`,\n )\n if (existingDevice) {\n return existingDevice\n }\n\n // Find the discovered camera by host (externalId === host)\n let discovered = this.lastDiscoveredCameras.find((c) => c.host === externalId)\n if (!discovered) {\n // Re-discover if not in cache\n this.ctx.logger.info(`Camera ${externalId} not in cache, re-discovering...`)\n const cameras = await discoverOnvifCameras()\n this.lastDiscoveredCameras = cameras\n discovered = cameras.find((c) => c.host === externalId)\n }\n if (!discovered) {\n throw new Error(`Camera with externalId \"${externalId}\" not found on network`)\n }\n\n const cameraId = externalId.replace(/\\./g, '-')\n const cameraConfig: OnvifCameraConfig = {\n id: cameraId,\n name: (config?.['name'] as string) ?? discovered.name ?? externalId,\n host: discovered.host,\n port: discovered.port,\n username: (config?.['username'] as string) ?? this.config.defaultUsername,\n password: (config?.['password'] as string) ?? this.config.defaultPassword,\n }\n\n await this.addCamera(cameraConfig)\n\n const device = this.devices.find((d) => d.id === `${this.id}/${cameraId}`)\n if (!device) {\n throw new Error(`Failed to create device for camera ${externalId}`)\n }\n\n // Persist adopted camera config so it survives restarts\n await this.persistAdoptedCamera(cameraConfig)\n\n this.ctx.logger.info(`Adopted camera ${cameraConfig.name} (${externalId})`)\n return device\n }\n\n private async persistAdoptedCamera(cam: OnvifCameraConfig): Promise<void> {\n const storage = this.ctx.storage\n if (!storage.structured) return\n\n try {\n const existing = await storage.structured.query('adopted-cameras', {\n where: { id: cam.id },\n limit: 1,\n })\n\n if (existing.length === 0) {\n await storage.structured.insert({\n collection: 'adopted-cameras',\n id: cam.id,\n data: { ...cam },\n })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn(`Failed to persist adopted camera ${cam.id}: ${message}`)\n }\n }\n\n getDevices(): IDevice[] {\n return [...this.devices]\n }\n\n getDeviceConfigSchema() {\n return {\n id: 'string',\n name: 'string',\n host: 'string (IP or hostname)',\n port: 'number (default: 80)',\n username: 'string (optional)',\n password: 'string (optional)',\n rtspUrl: 'string (optional, override ONVIF stream URI)',\n }\n }\n\n subscribeLiveEvents(_callback: (event: LiveEvent) => void): () => void {\n // ONVIF events via pipeline — no native event subscription here\n return () => {}\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n CapabilityProviderMap,\n ConfigUISchema,\n IConfigurable,\n} from '@camstack/types'\nimport { OnvifProvider } from './onvif-provider'\nimport type { OnvifProviderConfig } from './onvif-types'\n\nexport class OnvifProviderAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'provider-onvif',\n name: 'ONVIF Camera Provider',\n version: '0.1.0',\n description: 'Discovery automatica di camere ONVIF sulla rete locale',\n capabilities: ['device-provider'],\n }\n\n private provider: OnvifProvider | null = null\n\n async initialize(context: AddonContext): Promise<void> {\n const config = context.addonConfig as unknown as OnvifProviderConfig\n\n const providerConfig: OnvifProviderConfig = {\n id: config.id ?? 'onvif-default',\n name: config.name ?? 'ONVIF Cameras',\n discovery: config.discovery,\n cameras: config.cameras,\n defaultUsername: config.defaultUsername,\n defaultPassword: config.defaultPassword,\n }\n\n this.provider = new OnvifProvider(providerConfig, {\n id: context.id,\n logger: context.logger,\n eventBus: context.eventBus,\n storage: context.storage,\n config: context.config,\n })\n\n context.logger.info('ONVIF provider addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.provider?.stop()\n this.provider = null\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'device-provider' && this.provider) {\n return this.provider as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'discovery',\n title: 'ONVIF Discovery',\n description: 'Auto-discover ONVIF cameras on the local network',\n columns: 2,\n fields: [\n { type: 'boolean', key: 'discovery.enabled', label: 'Enable Auto-Discovery' },\n { type: 'number', key: 'discovery.timeout', label: 'Discovery Timeout', unit: 'ms', min: 1000, max: 30000, step: 1000 },\n ],\n },\n {\n id: 'credentials',\n title: 'Default Credentials',\n description: 'Default credentials for discovered cameras',\n columns: 2,\n fields: [\n { type: 'text', key: 'defaultUsername', label: 'Default Username' },\n { type: 'password', key: 'defaultPassword', label: 'Default Password', showToggle: true },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return {}\n }\n\n async onConfigChange(_config: Record<string, unknown>): Promise<void> {\n // Restart provider with new config\n }\n}\n"],"mappings":"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","names":["import_onvif"]}
|
package/dist/index.mjs
CHANGED
|
@@ -165,6 +165,7 @@ var OnvifClient = class {
|
|
|
165
165
|
};
|
|
166
166
|
|
|
167
167
|
// src/onvif-device.ts
|
|
168
|
+
import { DeviceType } from "@camstack/types";
|
|
168
169
|
var OnvifDevice = class {
|
|
169
170
|
constructor(client, config, ctx) {
|
|
170
171
|
this.client = client;
|
|
@@ -182,7 +183,7 @@ var OnvifDevice = class {
|
|
|
182
183
|
id;
|
|
183
184
|
name;
|
|
184
185
|
providerId;
|
|
185
|
-
type =
|
|
186
|
+
type = DeviceType.Camera;
|
|
186
187
|
capabilities;
|
|
187
188
|
ctx;
|
|
188
189
|
capabilityMap = /* @__PURE__ */ new Map();
|
|
@@ -424,6 +425,7 @@ var OnvifProvider = class {
|
|
|
424
425
|
ctx;
|
|
425
426
|
devices = [];
|
|
426
427
|
clients = /* @__PURE__ */ new Map();
|
|
428
|
+
lastDiscoveredCameras = [];
|
|
427
429
|
async start() {
|
|
428
430
|
if (this.config.discovery?.enabled !== false) {
|
|
429
431
|
const timeout = this.config.discovery?.timeout ?? 5e3;
|
|
@@ -444,6 +446,7 @@ var OnvifProvider = class {
|
|
|
444
446
|
for (const cam of this.config.cameras ?? []) {
|
|
445
447
|
await this.addCamera(cam);
|
|
446
448
|
}
|
|
449
|
+
await this.loadAdoptedCameras();
|
|
447
450
|
this.ctx.logger.info(
|
|
448
451
|
`ONVIF provider started with ${this.devices.length} camera(s)`
|
|
449
452
|
);
|
|
@@ -503,6 +506,26 @@ var OnvifProvider = class {
|
|
|
503
506
|
this.ctx.logger.warn(`Failed to connect to ${cam.host}: ${message}`);
|
|
504
507
|
}
|
|
505
508
|
}
|
|
509
|
+
async loadAdoptedCameras() {
|
|
510
|
+
const storage = this.ctx.storage;
|
|
511
|
+
if (!storage.structured) return;
|
|
512
|
+
try {
|
|
513
|
+
const records = await storage.structured.query("adopted-cameras", {});
|
|
514
|
+
for (const record of records) {
|
|
515
|
+
const cam = record.data;
|
|
516
|
+
const alreadyLoaded = this.devices.some(
|
|
517
|
+
(d) => d.id === `${this.id}/${cam.id}`
|
|
518
|
+
);
|
|
519
|
+
if (!alreadyLoaded) {
|
|
520
|
+
await this.addCamera(cam);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (records.length > 0) {
|
|
524
|
+
this.ctx.logger.info(`Restored ${records.length} adopted camera(s) from storage`);
|
|
525
|
+
}
|
|
526
|
+
} catch {
|
|
527
|
+
}
|
|
528
|
+
}
|
|
506
529
|
async stop() {
|
|
507
530
|
for (const client of this.clients.values()) {
|
|
508
531
|
client.disconnect();
|
|
@@ -516,6 +539,7 @@ var OnvifProvider = class {
|
|
|
516
539
|
}
|
|
517
540
|
async discoverDevices() {
|
|
518
541
|
const cameras = await discoverOnvifCameras();
|
|
542
|
+
this.lastDiscoveredCameras = cameras;
|
|
519
543
|
return cameras.map((c) => ({
|
|
520
544
|
externalId: c.host,
|
|
521
545
|
name: c.name ?? c.host,
|
|
@@ -524,6 +548,61 @@ var OnvifProvider = class {
|
|
|
524
548
|
metadata: { manufacturer: c.manufacturer, model: c.model }
|
|
525
549
|
}));
|
|
526
550
|
}
|
|
551
|
+
async adoptDevice(externalId, config) {
|
|
552
|
+
const existingDevice = this.devices.find(
|
|
553
|
+
(d) => d.id === `${this.id}/${externalId.replace(/\./g, "-")}`
|
|
554
|
+
);
|
|
555
|
+
if (existingDevice) {
|
|
556
|
+
return existingDevice;
|
|
557
|
+
}
|
|
558
|
+
let discovered = this.lastDiscoveredCameras.find((c) => c.host === externalId);
|
|
559
|
+
if (!discovered) {
|
|
560
|
+
this.ctx.logger.info(`Camera ${externalId} not in cache, re-discovering...`);
|
|
561
|
+
const cameras = await discoverOnvifCameras();
|
|
562
|
+
this.lastDiscoveredCameras = cameras;
|
|
563
|
+
discovered = cameras.find((c) => c.host === externalId);
|
|
564
|
+
}
|
|
565
|
+
if (!discovered) {
|
|
566
|
+
throw new Error(`Camera with externalId "${externalId}" not found on network`);
|
|
567
|
+
}
|
|
568
|
+
const cameraId = externalId.replace(/\./g, "-");
|
|
569
|
+
const cameraConfig = {
|
|
570
|
+
id: cameraId,
|
|
571
|
+
name: config?.["name"] ?? discovered.name ?? externalId,
|
|
572
|
+
host: discovered.host,
|
|
573
|
+
port: discovered.port,
|
|
574
|
+
username: config?.["username"] ?? this.config.defaultUsername,
|
|
575
|
+
password: config?.["password"] ?? this.config.defaultPassword
|
|
576
|
+
};
|
|
577
|
+
await this.addCamera(cameraConfig);
|
|
578
|
+
const device = this.devices.find((d) => d.id === `${this.id}/${cameraId}`);
|
|
579
|
+
if (!device) {
|
|
580
|
+
throw new Error(`Failed to create device for camera ${externalId}`);
|
|
581
|
+
}
|
|
582
|
+
await this.persistAdoptedCamera(cameraConfig);
|
|
583
|
+
this.ctx.logger.info(`Adopted camera ${cameraConfig.name} (${externalId})`);
|
|
584
|
+
return device;
|
|
585
|
+
}
|
|
586
|
+
async persistAdoptedCamera(cam) {
|
|
587
|
+
const storage = this.ctx.storage;
|
|
588
|
+
if (!storage.structured) return;
|
|
589
|
+
try {
|
|
590
|
+
const existing = await storage.structured.query("adopted-cameras", {
|
|
591
|
+
where: { id: cam.id },
|
|
592
|
+
limit: 1
|
|
593
|
+
});
|
|
594
|
+
if (existing.length === 0) {
|
|
595
|
+
await storage.structured.insert({
|
|
596
|
+
collection: "adopted-cameras",
|
|
597
|
+
id: cam.id,
|
|
598
|
+
data: { ...cam }
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
} catch (err) {
|
|
602
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
603
|
+
this.ctx.logger.warn(`Failed to persist adopted camera ${cam.id}: ${message}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
527
606
|
getDevices() {
|
|
528
607
|
return [...this.devices];
|
|
529
608
|
}
|
|
@@ -550,6 +629,7 @@ var OnvifProviderAddon = class {
|
|
|
550
629
|
id: "provider-onvif",
|
|
551
630
|
name: "ONVIF Camera Provider",
|
|
552
631
|
version: "0.1.0",
|
|
632
|
+
description: "Discovery automatica di camere ONVIF sulla rete locale",
|
|
553
633
|
capabilities: ["device-provider"]
|
|
554
634
|
};
|
|
555
635
|
provider = null;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/onvif-client.ts","../src/onvif-device.ts","../src/onvif-discovery.ts","../src/element-config-store.ts","../src/onvif-provider.ts","../src/addon.ts"],"sourcesContent":["import { Cam } from 'onvif'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport class OnvifClient {\n private cam: InstanceType<typeof Cam> | null = null\n\n constructor(\n private readonly host: string,\n private readonly port: number,\n private readonly username: string,\n private readonly password: string,\n private readonly logger: IScopedLogger,\n ) {}\n\n /** Connect to the camera */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.cam = new Cam(\n {\n hostname: this.host,\n port: this.port,\n username: this.username,\n password: this.password,\n },\n (err: Error | null) => {\n if (err) {\n reject(err)\n } else {\n this.logger.info(`Connected to ONVIF camera at ${this.host}:${this.port}`)\n resolve()\n }\n },\n )\n })\n }\n\n /** Get device info */\n async getDeviceInfo(): Promise<{\n manufacturer: string\n model: string\n firmwareVersion: string\n serialNumber: string\n }> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getDeviceInformation((err: Error | null, info: any) => {\n if (err) reject(err)\n else resolve(info)\n })\n })\n }\n\n /** Get RTSP stream URI */\n async getStreamUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = { protocol: 'RTSP' }\n if (profileToken) options.profileToken = profileToken\n this.cam.getStreamUri(options, (err: Error | null, stream: any) => {\n if (err) reject(err)\n else resolve(stream.uri)\n })\n })\n }\n\n /** Get available media profiles */\n async getProfiles(): Promise<\n Array<{ token: string; name: string; videoWidth?: number; videoHeight?: number }>\n > {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getProfiles((err: Error | null, profiles: any[]) => {\n if (err) reject(err)\n else\n resolve(\n profiles.map((p: any) => ({\n token: p.$.token ?? p.token,\n name: p.name,\n videoWidth: p.videoEncoderConfiguration?.resolution?.width,\n videoHeight: p.videoEncoderConfiguration?.resolution?.height,\n })),\n )\n })\n })\n }\n\n /** Get snapshot URI */\n async getSnapshotUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = {}\n if (profileToken) options.profileToken = profileToken\n this.cam.getSnapshotUri(options, (err: Error | null, res: any) => {\n if (err) reject(err)\n else resolve(res.uri)\n })\n })\n }\n\n /** Check if PTZ is supported */\n hasPtz(): boolean {\n return (this.cam as any)?.ptzUri != null\n }\n\n /** PTZ move (continuous) */\n async ptzMove(options: {\n x?: number\n y?: number\n zoom?: number\n speed?: number\n }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.continuousMove(\n {\n x: options.x ?? 0,\n y: options.y ?? 0,\n zoom: options.zoom ?? 0,\n timeout: 1000,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** PTZ stop */\n async ptzStop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.stop({}, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n /** PTZ absolute move */\n async ptzAbsoluteMove(options: { x: number; y: number; zoom: number }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.absoluteMove(\n {\n x: options.x,\n y: options.y,\n zoom: options.zoom,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** Get PTZ presets */\n async getPtzPresets(): Promise<Array<{ token: string; name: string }>> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getPresets({}, (err: Error | null, presets: any) => {\n if (err) reject(err)\n else {\n const list = Array.isArray(presets) ? presets : [presets]\n resolve(\n list.filter(Boolean).map((p: any) => ({\n token: p.$.token ?? String(p.token),\n name: p.name ?? p.$.token ?? 'Preset',\n })),\n )\n }\n })\n })\n }\n\n /** Go to PTZ preset */\n async gotoPreset(presetToken: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.gotoPreset({ preset: presetToken }, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n disconnect(): void {\n this.cam = null\n }\n}\n","import type {\n IDevice,\n DeviceType,\n DeviceState,\n DeviceMetadata,\n DeviceCapabilityName,\n IDeviceCapability,\n CamstackContext,\n ICamera,\n StreamOption,\n ConnectionMode,\n IPanTiltZoom,\n} from '@camstack/types'\nimport type { OnvifClient } from './onvif-client'\n\nexport interface OnvifDeviceConfig {\n readonly cameraId: string\n readonly cameraName: string\n readonly providerId: string\n readonly rtspUrl: string\n readonly subStreamUrl?: string\n readonly snapshotUrl?: string\n readonly hasPtz: boolean\n readonly profiles: ReadonlyArray<{\n token: string\n name: string\n videoWidth?: number\n videoHeight?: number\n }>\n readonly manufacturer?: string\n readonly model?: string\n readonly firmware?: string\n}\n\nexport class OnvifDevice implements IDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly type: DeviceType = 'camera'\n readonly capabilities: DeviceCapabilityName[]\n readonly ctx: CamstackContext\n\n private readonly capabilityMap = new Map<DeviceCapabilityName, IDeviceCapability>()\n\n constructor(\n private readonly client: OnvifClient,\n private readonly config: OnvifDeviceConfig,\n ctx: CamstackContext,\n ) {\n this.id = `${config.providerId}/${config.cameraId}`\n this.name = config.cameraName\n this.providerId = config.providerId\n this.ctx = ctx\n\n const caps: DeviceCapabilityName[] = ['camera']\n if (config.hasPtz) caps.push('panTiltZoom')\n this.capabilities = caps\n\n this.capabilityMap.set('camera', this.createCamera())\n if (config.hasPtz) this.capabilityMap.set('panTiltZoom', this.createPtz())\n }\n\n getCapability<T extends IDeviceCapability>(cap: DeviceCapabilityName): T | null {\n return (this.capabilityMap.get(cap) as T) ?? null\n }\n\n hasCapability(cap: DeviceCapabilityName): boolean {\n return this.capabilityMap.has(cap)\n }\n\n getState(): DeviceState {\n return { online: true }\n }\n\n getMetadata(): DeviceMetadata {\n return {\n manufacturer: this.config.manufacturer ?? 'ONVIF',\n model: this.config.model,\n firmware: this.config.firmware,\n }\n }\n\n private createCamera(): ICamera {\n const { config } = this\n return {\n kind: 'camera',\n\n async getSnapshot() {\n if (config.snapshotUrl) {\n const res = await fetch(config.snapshotUrl)\n return Buffer.from(await res.arrayBuffer())\n }\n return Buffer.alloc(0)\n },\n\n async getStreamOptions(): Promise<StreamOption[]> {\n const options: StreamOption[] = [\n {\n id: `${config.cameraId}_main`,\n label: 'Main',\n protocol: 'rtsp',\n quality: 'main',\n url: config.rtspUrl,\n },\n ]\n if (config.subStreamUrl) {\n options.push({\n id: `${config.cameraId}_sub`,\n label: 'Sub',\n protocol: 'rtsp',\n quality: 'sub',\n url: config.subStreamUrl,\n })\n }\n return options\n },\n\n async getStreamUrl(option: StreamOption) {\n return option.url ?? config.rtspUrl\n },\n\n getConnectionMode(): ConnectionMode {\n return 'on-demand'\n },\n\n async setConnectionMode() {},\n }\n }\n\n private createPtz(): IPanTiltZoom {\n const { client } = this\n return {\n kind: 'panTiltZoom',\n\n async move(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom, speed: cmd.speed })\n },\n\n async continuousMove(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom })\n },\n\n async stop() {\n await client.ptzStop()\n },\n\n async getPresets() {\n const presets = await client.getPtzPresets()\n return presets.map((p) => ({ id: p.token, name: p.name }))\n },\n\n async goToPreset(presetId: string) {\n await client.gotoPreset(presetId)\n },\n\n async goHome() {\n await client.ptzAbsoluteMove({ x: 0, y: 0, zoom: 0 })\n },\n\n async getPosition() {\n return { pan: 0, tilt: 0, zoom: 0 }\n },\n }\n }\n}\n","import { Discovery } from 'onvif'\nimport type { DiscoveredOnvifCamera } from './onvif-types'\n\n/**\n * Discovers ONVIF cameras on the local network via WS-Discovery.\n * Returns a list of found cameras after the given timeout.\n */\nexport async function discoverOnvifCameras(\n timeout: number = 5000,\n): Promise<readonly DiscoveredOnvifCamera[]> {\n return new Promise((resolve) => {\n const cameras: DiscoveredOnvifCamera[] = []\n\n Discovery.on('device', (cam: any) => {\n cameras.push({\n host: cam.hostname,\n port: cam.port ?? 80,\n name: cam.name,\n manufacturer: cam.manufacturer,\n model: cam.model,\n scopes: cam.scopes,\n })\n })\n\n Discovery.probe({ timeout })\n\n setTimeout(() => {\n Discovery.removeAllListeners('device')\n resolve(cameras)\n }, timeout + 500)\n })\n}\n","import type { IElementConfig } from '@camstack/types'\nimport type { IStorageLocation } from '@camstack/types'\n\n/**\n * Persisted config store for a single element.\n * Reads/writes to the element's scoped storage under the 'config' collection.\n * Notifies listeners on every change.\n */\nexport class ElementConfigStore implements IElementConfig {\n private cache: Record<string, unknown> = {}\n private listeners: Set<(config: Record<string, unknown>) => void> = new Set()\n private loaded = false\n\n constructor(\n private readonly elementId: string,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Load config from storage into cache. Called once on first access. */\n private async ensureLoaded(): Promise<void> {\n if (this.loaded) return\n if (!this.storage.structured) {\n this.loaded = true\n return\n }\n\n try {\n const records = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n if (records.length > 0) {\n this.cache = (records[0] as any).data ?? {}\n }\n } catch {\n // Storage might not be ready yet\n }\n this.loaded = true\n }\n\n getAll(): Record<string, unknown> {\n return { ...this.cache }\n }\n\n get<T = unknown>(key: string): T | undefined {\n const parts = key.split('.')\n let current: unknown = this.cache\n for (const part of parts) {\n if (current == null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[part]\n }\n return current as T | undefined\n }\n\n async set(key: string, value: unknown): Promise<void> {\n await this.ensureLoaded()\n setNestedValue(this.cache, key, value)\n await this.persist()\n this.notifyListeners()\n }\n\n async setAll(config: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n this.cache = { ...config }\n await this.persist()\n this.notifyListeners()\n }\n\n onChange(callback: (config: Record<string, unknown>) => void): () => void {\n this.listeners.add(callback)\n return () => { this.listeners.delete(callback) }\n }\n\n /** Initialize from storage — called by ContextFactory after creation */\n async load(): Promise<void> {\n await this.ensureLoaded()\n }\n\n /** Initialize with default values (doesn't overwrite existing) */\n async loadDefaults(defaults: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n if (Object.keys(this.cache).length === 0) {\n this.cache = { ...defaults }\n await this.persist()\n }\n }\n\n private async persist(): Promise<void> {\n if (!this.storage.structured) return\n\n try {\n const existing = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n\n if (existing.length > 0) {\n await this.storage.structured.update('config', this.elementId, this.cache)\n } else {\n await this.storage.structured.insert({\n collection: 'config',\n id: this.elementId,\n data: this.cache,\n })\n }\n } catch {\n // Storage might not be ready\n }\n }\n\n private notifyListeners(): void {\n const snapshot = this.getAll()\n for (const listener of this.listeners) {\n try {\n listener(snapshot)\n } catch {\n // Don't let one bad listener kill others\n }\n }\n }\n}\n\nfunction setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split('.')\n let current: Record<string, unknown> = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n current[parts[parts.length - 1]!] = value\n}\n","import { OnvifClient } from './onvif-client'\nimport { OnvifDevice } from './onvif-device'\nimport { discoverOnvifCameras } from './onvif-discovery'\nimport { ElementConfigStore } from './element-config-store'\nimport type {\n IDeviceProvider,\n ProviderStatus,\n DiscoveredDevice,\n LiveEvent,\n IDevice,\n DeviceType,\n DeviceCapabilityName,\n CamstackContext,\n} from '@camstack/types'\nimport type { OnvifProviderConfig, OnvifCameraConfig } from './onvif-types'\n\nexport class OnvifProvider implements IDeviceProvider {\n readonly id: string\n readonly type = 'onvif'\n readonly name: string\n readonly discoveryMode: 'both' = 'both'\n readonly ctx: CamstackContext\n\n private devices: OnvifDevice[] = []\n private readonly clients: Map<string, OnvifClient> = new Map()\n\n constructor(\n private readonly config: OnvifProviderConfig,\n ctx: CamstackContext,\n ) {\n this.id = config.id\n this.name = config.name\n this.ctx = ctx\n }\n\n async start(): Promise<void> {\n // 1. Auto-discover cameras on LAN (if enabled)\n if (this.config.discovery?.enabled !== false) {\n const timeout = this.config.discovery?.timeout ?? 5000\n this.ctx.logger.info(`Starting ONVIF discovery (timeout: ${timeout}ms)`)\n\n const discovered = await discoverOnvifCameras(timeout)\n this.ctx.logger.info(`Discovered ${discovered.length} ONVIF camera(s)`)\n\n for (const cam of discovered) {\n await this.addCamera({\n id: cam.host.replace(/\\./g, '-'),\n name: cam.name ?? cam.host,\n host: cam.host,\n port: cam.port,\n username: this.config.defaultUsername,\n password: this.config.defaultPassword,\n })\n }\n }\n\n // 2. Add manually configured cameras\n for (const cam of this.config.cameras ?? []) {\n await this.addCamera(cam)\n }\n\n this.ctx.logger.info(\n `ONVIF provider started with ${this.devices.length} camera(s)`,\n )\n }\n\n private async addCamera(cam: OnvifCameraConfig): Promise<void> {\n try {\n const client = new OnvifClient(\n cam.host,\n cam.port ?? 80,\n cam.username ?? '',\n cam.password ?? '',\n this.ctx.logger.child(cam.name),\n )\n await client.connect()\n\n const info = await client.getDeviceInfo()\n const profiles = await client.getProfiles()\n const mainProfile = profiles[0]\n const subProfile = profiles.length > 1 ? profiles[1] : undefined\n\n const rtspUrl = cam.rtspUrl ?? (await client.getStreamUri(mainProfile?.token))\n const subStreamUrl = subProfile\n ? await client.getStreamUri(subProfile.token)\n : undefined\n\n let snapshotUrl: string | undefined\n try {\n snapshotUrl = await client.getSnapshotUri(mainProfile?.token)\n } catch {\n // Snapshot not supported by this camera\n }\n\n const deviceCtx: CamstackContext = {\n id: `device:${this.id}/${cam.id}`,\n logger: this.ctx.logger.child(cam.name),\n eventBus: this.ctx.eventBus,\n storage: this.ctx.storage,\n config: new ElementConfigStore(`device:${this.id}/${cam.id}`, this.ctx.storage),\n }\n\n const device = new OnvifDevice(\n client,\n {\n cameraId: cam.id,\n cameraName: cam.name,\n providerId: this.id,\n rtspUrl,\n subStreamUrl,\n snapshotUrl,\n hasPtz: client.hasPtz(),\n profiles,\n manufacturer: info.manufacturer,\n model: info.model,\n firmware: info.firmwareVersion,\n },\n deviceCtx,\n )\n\n this.devices = [...this.devices, device]\n this.clients.set(cam.id, client)\n this.ctx.logger.info(\n `Camera ${cam.name} (${cam.host}) connected — PTZ: ${client.hasPtz()}, profiles: ${profiles.length}`,\n )\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn(`Failed to connect to ${cam.host}: ${message}`)\n }\n }\n\n async stop(): Promise<void> {\n for (const client of this.clients.values()) {\n client.disconnect()\n }\n this.devices = []\n this.clients.clear()\n this.ctx.logger.info('ONVIF provider stopped')\n }\n\n getStatus(): ProviderStatus {\n return { connected: true, deviceCount: this.devices.length }\n }\n\n async discoverDevices(): Promise<DiscoveredDevice[]> {\n const cameras = await discoverOnvifCameras()\n return cameras.map((c) => ({\n externalId: c.host,\n name: c.name ?? c.host,\n type: 'camera' as DeviceType,\n capabilities: ['camera'] as DeviceCapabilityName[],\n metadata: { manufacturer: c.manufacturer, model: c.model },\n }))\n }\n\n getDevices(): IDevice[] {\n return [...this.devices]\n }\n\n getDeviceConfigSchema() {\n return {\n id: 'string',\n name: 'string',\n host: 'string (IP or hostname)',\n port: 'number (default: 80)',\n username: 'string (optional)',\n password: 'string (optional)',\n rtspUrl: 'string (optional, override ONVIF stream URI)',\n }\n }\n\n subscribeLiveEvents(_callback: (event: LiveEvent) => void): () => void {\n // ONVIF events via pipeline — no native event subscription here\n return () => {}\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n CapabilityProviderMap,\n ConfigUISchema,\n IConfigurable,\n} from '@camstack/types'\nimport { OnvifProvider } from './onvif-provider'\nimport type { OnvifProviderConfig } from './onvif-types'\n\nexport class OnvifProviderAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'provider-onvif',\n name: 'ONVIF Camera Provider',\n version: '0.1.0',\n capabilities: ['device-provider'],\n }\n\n private provider: OnvifProvider | null = null\n\n async initialize(context: AddonContext): Promise<void> {\n const config = context.addonConfig as unknown as OnvifProviderConfig\n\n const providerConfig: OnvifProviderConfig = {\n id: config.id ?? 'onvif-default',\n name: config.name ?? 'ONVIF Cameras',\n discovery: config.discovery,\n cameras: config.cameras,\n defaultUsername: config.defaultUsername,\n defaultPassword: config.defaultPassword,\n }\n\n this.provider = new OnvifProvider(providerConfig, {\n id: context.id,\n logger: context.logger,\n eventBus: context.eventBus,\n storage: context.storage,\n config: context.config,\n })\n\n context.logger.info('ONVIF provider addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.provider?.stop()\n this.provider = null\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'device-provider' && this.provider) {\n return this.provider as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'discovery',\n title: 'ONVIF Discovery',\n description: 'Auto-discover ONVIF cameras on the local network',\n columns: 2,\n fields: [\n { type: 'boolean', key: 'discovery.enabled', label: 'Enable Auto-Discovery' },\n { type: 'number', key: 'discovery.timeout', label: 'Discovery Timeout', unit: 'ms', min: 1000, max: 30000, step: 1000 },\n ],\n },\n {\n id: 'credentials',\n title: 'Default Credentials',\n description: 'Default credentials for discovered cameras',\n columns: 2,\n fields: [\n { type: 'text', key: 'defaultUsername', label: 'Default Username' },\n { type: 'password', key: 'defaultPassword', label: 'Default Password', showToggle: true },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return {}\n }\n\n async onConfigChange(_config: Record<string, unknown>): Promise<void> {\n // Restart provider with new config\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/onvif-client.ts","../src/onvif-device.ts","../src/onvif-discovery.ts","../src/element-config-store.ts","../src/onvif-provider.ts","../src/addon.ts"],"sourcesContent":["import { Cam } from 'onvif'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport class OnvifClient {\n private cam: InstanceType<typeof Cam> | null = null\n\n constructor(\n private readonly host: string,\n private readonly port: number,\n private readonly username: string,\n private readonly password: string,\n private readonly logger: IScopedLogger,\n ) {}\n\n /** Connect to the camera */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.cam = new Cam(\n {\n hostname: this.host,\n port: this.port,\n username: this.username,\n password: this.password,\n },\n (err: Error | null) => {\n if (err) {\n reject(err)\n } else {\n this.logger.info(`Connected to ONVIF camera at ${this.host}:${this.port}`)\n resolve()\n }\n },\n )\n })\n }\n\n /** Get device info */\n async getDeviceInfo(): Promise<{\n manufacturer: string\n model: string\n firmwareVersion: string\n serialNumber: string\n }> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getDeviceInformation((err: Error | null, info: any) => {\n if (err) reject(err)\n else resolve(info)\n })\n })\n }\n\n /** Get RTSP stream URI */\n async getStreamUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = { protocol: 'RTSP' }\n if (profileToken) options.profileToken = profileToken\n this.cam.getStreamUri(options, (err: Error | null, stream: any) => {\n if (err) reject(err)\n else resolve(stream.uri)\n })\n })\n }\n\n /** Get available media profiles */\n async getProfiles(): Promise<\n Array<{ token: string; name: string; videoWidth?: number; videoHeight?: number }>\n > {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getProfiles((err: Error | null, profiles: any[]) => {\n if (err) reject(err)\n else\n resolve(\n profiles.map((p: any) => ({\n token: p.$.token ?? p.token,\n name: p.name,\n videoWidth: p.videoEncoderConfiguration?.resolution?.width,\n videoHeight: p.videoEncoderConfiguration?.resolution?.height,\n })),\n )\n })\n })\n }\n\n /** Get snapshot URI */\n async getSnapshotUri(profileToken?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n const options: Record<string, unknown> = {}\n if (profileToken) options.profileToken = profileToken\n this.cam.getSnapshotUri(options, (err: Error | null, res: any) => {\n if (err) reject(err)\n else resolve(res.uri)\n })\n })\n }\n\n /** Check if PTZ is supported */\n hasPtz(): boolean {\n return (this.cam as any)?.ptzUri != null\n }\n\n /** PTZ move (continuous) */\n async ptzMove(options: {\n x?: number\n y?: number\n zoom?: number\n speed?: number\n }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.continuousMove(\n {\n x: options.x ?? 0,\n y: options.y ?? 0,\n zoom: options.zoom ?? 0,\n timeout: 1000,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** PTZ stop */\n async ptzStop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.stop({}, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n /** PTZ absolute move */\n async ptzAbsoluteMove(options: { x: number; y: number; zoom: number }): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.absoluteMove(\n {\n x: options.x,\n y: options.y,\n zoom: options.zoom,\n },\n (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n },\n )\n })\n }\n\n /** Get PTZ presets */\n async getPtzPresets(): Promise<Array<{ token: string; name: string }>> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.getPresets({}, (err: Error | null, presets: any) => {\n if (err) reject(err)\n else {\n const list = Array.isArray(presets) ? presets : [presets]\n resolve(\n list.filter(Boolean).map((p: any) => ({\n token: p.$.token ?? String(p.token),\n name: p.name ?? p.$.token ?? 'Preset',\n })),\n )\n }\n })\n })\n }\n\n /** Go to PTZ preset */\n async gotoPreset(presetToken: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.cam) return reject(new Error('Not connected'))\n this.cam.gotoPreset({ preset: presetToken }, (err: Error | null) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n disconnect(): void {\n this.cam = null\n }\n}\n","import { DeviceType } from '@camstack/types'\nimport type {\n IDevice,\n DeviceState,\n DeviceMetadata,\n DeviceCapabilityName,\n IDeviceCapability,\n CamstackContext,\n ICamera,\n StreamOption,\n ConnectionMode,\n IPanTiltZoom,\n} from '@camstack/types'\nimport type { OnvifClient } from './onvif-client'\n\nexport interface OnvifDeviceConfig {\n readonly cameraId: string\n readonly cameraName: string\n readonly providerId: string\n readonly rtspUrl: string\n readonly subStreamUrl?: string\n readonly snapshotUrl?: string\n readonly hasPtz: boolean\n readonly profiles: ReadonlyArray<{\n token: string\n name: string\n videoWidth?: number\n videoHeight?: number\n }>\n readonly manufacturer?: string\n readonly model?: string\n readonly firmware?: string\n}\n\nexport class OnvifDevice implements IDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly type: DeviceType = DeviceType.Camera\n readonly capabilities: DeviceCapabilityName[]\n readonly ctx: CamstackContext\n\n private readonly capabilityMap = new Map<DeviceCapabilityName, IDeviceCapability>()\n\n constructor(\n private readonly client: OnvifClient,\n private readonly config: OnvifDeviceConfig,\n ctx: CamstackContext,\n ) {\n this.id = `${config.providerId}/${config.cameraId}`\n this.name = config.cameraName\n this.providerId = config.providerId\n this.ctx = ctx\n\n const caps: DeviceCapabilityName[] = ['camera']\n if (config.hasPtz) caps.push('panTiltZoom')\n this.capabilities = caps\n\n this.capabilityMap.set('camera', this.createCamera())\n if (config.hasPtz) this.capabilityMap.set('panTiltZoom', this.createPtz())\n }\n\n getCapability<T extends IDeviceCapability>(cap: DeviceCapabilityName): T | null {\n return (this.capabilityMap.get(cap) as T) ?? null\n }\n\n hasCapability(cap: DeviceCapabilityName): boolean {\n return this.capabilityMap.has(cap)\n }\n\n getState(): DeviceState {\n return { online: true }\n }\n\n getMetadata(): DeviceMetadata {\n return {\n manufacturer: this.config.manufacturer ?? 'ONVIF',\n model: this.config.model,\n firmware: this.config.firmware,\n }\n }\n\n private createCamera(): ICamera {\n const { config } = this\n return {\n kind: 'camera',\n\n async getSnapshot() {\n if (config.snapshotUrl) {\n const res = await fetch(config.snapshotUrl)\n return Buffer.from(await res.arrayBuffer())\n }\n return Buffer.alloc(0)\n },\n\n async getStreamOptions(): Promise<StreamOption[]> {\n const options: StreamOption[] = [\n {\n id: `${config.cameraId}_main`,\n label: 'Main',\n protocol: 'rtsp',\n quality: 'main',\n url: config.rtspUrl,\n },\n ]\n if (config.subStreamUrl) {\n options.push({\n id: `${config.cameraId}_sub`,\n label: 'Sub',\n protocol: 'rtsp',\n quality: 'sub',\n url: config.subStreamUrl,\n })\n }\n return options\n },\n\n async getStreamUrl(option: StreamOption) {\n return option.url ?? config.rtspUrl\n },\n\n getConnectionMode(): ConnectionMode {\n return 'on-demand'\n },\n\n async setConnectionMode() {},\n }\n }\n\n private createPtz(): IPanTiltZoom {\n const { client } = this\n return {\n kind: 'panTiltZoom',\n\n async move(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom, speed: cmd.speed })\n },\n\n async continuousMove(cmd) {\n await client.ptzMove({ x: cmd.pan, y: cmd.tilt, zoom: cmd.zoom })\n },\n\n async stop() {\n await client.ptzStop()\n },\n\n async getPresets() {\n const presets = await client.getPtzPresets()\n return presets.map((p) => ({ id: p.token, name: p.name }))\n },\n\n async goToPreset(presetId: string) {\n await client.gotoPreset(presetId)\n },\n\n async goHome() {\n await client.ptzAbsoluteMove({ x: 0, y: 0, zoom: 0 })\n },\n\n async getPosition() {\n return { pan: 0, tilt: 0, zoom: 0 }\n },\n }\n }\n}\n","import { Discovery } from 'onvif'\nimport type { DiscoveredOnvifCamera } from './onvif-types'\n\n/**\n * Discovers ONVIF cameras on the local network via WS-Discovery.\n * Returns a list of found cameras after the given timeout.\n */\nexport async function discoverOnvifCameras(\n timeout: number = 5000,\n): Promise<readonly DiscoveredOnvifCamera[]> {\n return new Promise((resolve) => {\n const cameras: DiscoveredOnvifCamera[] = []\n\n Discovery.on('device', (cam: any) => {\n cameras.push({\n host: cam.hostname,\n port: cam.port ?? 80,\n name: cam.name,\n manufacturer: cam.manufacturer,\n model: cam.model,\n scopes: cam.scopes,\n })\n })\n\n Discovery.probe({ timeout })\n\n setTimeout(() => {\n Discovery.removeAllListeners('device')\n resolve(cameras)\n }, timeout + 500)\n })\n}\n","import type { IElementConfig } from '@camstack/types'\nimport type { IStorageLocation } from '@camstack/types'\n\n/**\n * Persisted config store for a single element.\n * Reads/writes to the element's scoped storage under the 'config' collection.\n * Notifies listeners on every change.\n */\nexport class ElementConfigStore implements IElementConfig {\n private cache: Record<string, unknown> = {}\n private listeners: Set<(config: Record<string, unknown>) => void> = new Set()\n private loaded = false\n\n constructor(\n private readonly elementId: string,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Load config from storage into cache. Called once on first access. */\n private async ensureLoaded(): Promise<void> {\n if (this.loaded) return\n if (!this.storage.structured) {\n this.loaded = true\n return\n }\n\n try {\n const records = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n if (records.length > 0) {\n this.cache = (records[0] as any).data ?? {}\n }\n } catch {\n // Storage might not be ready yet\n }\n this.loaded = true\n }\n\n getAll(): Record<string, unknown> {\n return { ...this.cache }\n }\n\n get<T = unknown>(key: string): T | undefined {\n const parts = key.split('.')\n let current: unknown = this.cache\n for (const part of parts) {\n if (current == null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[part]\n }\n return current as T | undefined\n }\n\n async set(key: string, value: unknown): Promise<void> {\n await this.ensureLoaded()\n setNestedValue(this.cache, key, value)\n await this.persist()\n this.notifyListeners()\n }\n\n async setAll(config: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n this.cache = { ...config }\n await this.persist()\n this.notifyListeners()\n }\n\n onChange(callback: (config: Record<string, unknown>) => void): () => void {\n this.listeners.add(callback)\n return () => { this.listeners.delete(callback) }\n }\n\n /** Initialize from storage — called by ContextFactory after creation */\n async load(): Promise<void> {\n await this.ensureLoaded()\n }\n\n /** Initialize with default values (doesn't overwrite existing) */\n async loadDefaults(defaults: Record<string, unknown>): Promise<void> {\n await this.ensureLoaded()\n if (Object.keys(this.cache).length === 0) {\n this.cache = { ...defaults }\n await this.persist()\n }\n }\n\n private async persist(): Promise<void> {\n if (!this.storage.structured) return\n\n try {\n const existing = await this.storage.structured.query('config', {\n where: { id: this.elementId },\n limit: 1,\n })\n\n if (existing.length > 0) {\n await this.storage.structured.update('config', this.elementId, this.cache)\n } else {\n await this.storage.structured.insert({\n collection: 'config',\n id: this.elementId,\n data: this.cache,\n })\n }\n } catch {\n // Storage might not be ready\n }\n }\n\n private notifyListeners(): void {\n const snapshot = this.getAll()\n for (const listener of this.listeners) {\n try {\n listener(snapshot)\n } catch {\n // Don't let one bad listener kill others\n }\n }\n }\n}\n\nfunction setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split('.')\n let current: Record<string, unknown> = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n current[parts[parts.length - 1]!] = value\n}\n","import { OnvifClient } from './onvif-client'\nimport { OnvifDevice } from './onvif-device'\nimport { discoverOnvifCameras } from './onvif-discovery'\nimport { ElementConfigStore } from './element-config-store'\nimport type {\n IDeviceProvider,\n ProviderStatus,\n DiscoveredDevice,\n LiveEvent,\n IDevice,\n DeviceType,\n DeviceCapabilityName,\n CamstackContext,\n} from '@camstack/types'\nimport type { OnvifProviderConfig, OnvifCameraConfig, DiscoveredOnvifCamera } from './onvif-types'\n\nexport class OnvifProvider implements IDeviceProvider {\n readonly id: string\n readonly type = 'onvif'\n readonly name: string\n readonly discoveryMode: 'both' = 'both'\n readonly ctx: CamstackContext\n\n private devices: OnvifDevice[] = []\n private readonly clients: Map<string, OnvifClient> = new Map()\n private lastDiscoveredCameras: readonly DiscoveredOnvifCamera[] = []\n\n constructor(\n private readonly config: OnvifProviderConfig,\n ctx: CamstackContext,\n ) {\n this.id = config.id\n this.name = config.name\n this.ctx = ctx\n }\n\n async start(): Promise<void> {\n // 1. Auto-discover cameras on LAN (if enabled)\n if (this.config.discovery?.enabled !== false) {\n const timeout = this.config.discovery?.timeout ?? 5000\n this.ctx.logger.info(`Starting ONVIF discovery (timeout: ${timeout}ms)`)\n\n const discovered = await discoverOnvifCameras(timeout)\n this.ctx.logger.info(`Discovered ${discovered.length} ONVIF camera(s)`)\n\n for (const cam of discovered) {\n await this.addCamera({\n id: cam.host.replace(/\\./g, '-'),\n name: cam.name ?? cam.host,\n host: cam.host,\n port: cam.port,\n username: this.config.defaultUsername,\n password: this.config.defaultPassword,\n })\n }\n }\n\n // 2. Add manually configured cameras\n for (const cam of this.config.cameras ?? []) {\n await this.addCamera(cam)\n }\n\n // 3. Restore previously adopted cameras from storage\n await this.loadAdoptedCameras()\n\n this.ctx.logger.info(\n `ONVIF provider started with ${this.devices.length} camera(s)`,\n )\n }\n\n private async addCamera(cam: OnvifCameraConfig): Promise<void> {\n try {\n const client = new OnvifClient(\n cam.host,\n cam.port ?? 80,\n cam.username ?? '',\n cam.password ?? '',\n this.ctx.logger.child(cam.name),\n )\n await client.connect()\n\n const info = await client.getDeviceInfo()\n const profiles = await client.getProfiles()\n const mainProfile = profiles[0]\n const subProfile = profiles.length > 1 ? profiles[1] : undefined\n\n const rtspUrl = cam.rtspUrl ?? (await client.getStreamUri(mainProfile?.token))\n const subStreamUrl = subProfile\n ? await client.getStreamUri(subProfile.token)\n : undefined\n\n let snapshotUrl: string | undefined\n try {\n snapshotUrl = await client.getSnapshotUri(mainProfile?.token)\n } catch {\n // Snapshot not supported by this camera\n }\n\n const deviceCtx: CamstackContext = {\n id: `device:${this.id}/${cam.id}`,\n logger: this.ctx.logger.child(cam.name),\n eventBus: this.ctx.eventBus,\n storage: this.ctx.storage,\n config: new ElementConfigStore(`device:${this.id}/${cam.id}`, this.ctx.storage),\n }\n\n const device = new OnvifDevice(\n client,\n {\n cameraId: cam.id,\n cameraName: cam.name,\n providerId: this.id,\n rtspUrl,\n subStreamUrl,\n snapshotUrl,\n hasPtz: client.hasPtz(),\n profiles,\n manufacturer: info.manufacturer,\n model: info.model,\n firmware: info.firmwareVersion,\n },\n deviceCtx,\n )\n\n this.devices = [...this.devices, device]\n this.clients.set(cam.id, client)\n this.ctx.logger.info(\n `Camera ${cam.name} (${cam.host}) connected — PTZ: ${client.hasPtz()}, profiles: ${profiles.length}`,\n )\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn(`Failed to connect to ${cam.host}: ${message}`)\n }\n }\n\n private async loadAdoptedCameras(): Promise<void> {\n const storage = this.ctx.storage\n if (!storage.structured) return\n\n try {\n const records = await storage.structured.query('adopted-cameras', {})\n for (const record of records) {\n const cam = (record as any).data as OnvifCameraConfig\n // Skip if already loaded (e.g. matched by manual config or discovery)\n const alreadyLoaded = this.devices.some(\n (d) => d.id === `${this.id}/${cam.id}`,\n )\n if (!alreadyLoaded) {\n await this.addCamera(cam)\n }\n }\n if (records.length > 0) {\n this.ctx.logger.info(`Restored ${records.length} adopted camera(s) from storage`)\n }\n } catch {\n // Storage might not be ready yet\n }\n }\n\n async stop(): Promise<void> {\n for (const client of this.clients.values()) {\n client.disconnect()\n }\n this.devices = []\n this.clients.clear()\n this.ctx.logger.info('ONVIF provider stopped')\n }\n\n getStatus(): ProviderStatus {\n return { connected: true, deviceCount: this.devices.length }\n }\n\n async discoverDevices(): Promise<DiscoveredDevice[]> {\n const cameras = await discoverOnvifCameras()\n this.lastDiscoveredCameras = cameras\n return cameras.map((c) => ({\n externalId: c.host,\n name: c.name ?? c.host,\n type: 'camera' as DeviceType,\n capabilities: ['camera'] as DeviceCapabilityName[],\n metadata: { manufacturer: c.manufacturer, model: c.model },\n }))\n }\n\n async adoptDevice(externalId: string, config?: Record<string, unknown>): Promise<IDevice> {\n // Check if already adopted\n const existingDevice = this.devices.find(\n (d) => d.id === `${this.id}/${externalId.replace(/\\./g, '-')}`,\n )\n if (existingDevice) {\n return existingDevice\n }\n\n // Find the discovered camera by host (externalId === host)\n let discovered = this.lastDiscoveredCameras.find((c) => c.host === externalId)\n if (!discovered) {\n // Re-discover if not in cache\n this.ctx.logger.info(`Camera ${externalId} not in cache, re-discovering...`)\n const cameras = await discoverOnvifCameras()\n this.lastDiscoveredCameras = cameras\n discovered = cameras.find((c) => c.host === externalId)\n }\n if (!discovered) {\n throw new Error(`Camera with externalId \"${externalId}\" not found on network`)\n }\n\n const cameraId = externalId.replace(/\\./g, '-')\n const cameraConfig: OnvifCameraConfig = {\n id: cameraId,\n name: (config?.['name'] as string) ?? discovered.name ?? externalId,\n host: discovered.host,\n port: discovered.port,\n username: (config?.['username'] as string) ?? this.config.defaultUsername,\n password: (config?.['password'] as string) ?? this.config.defaultPassword,\n }\n\n await this.addCamera(cameraConfig)\n\n const device = this.devices.find((d) => d.id === `${this.id}/${cameraId}`)\n if (!device) {\n throw new Error(`Failed to create device for camera ${externalId}`)\n }\n\n // Persist adopted camera config so it survives restarts\n await this.persistAdoptedCamera(cameraConfig)\n\n this.ctx.logger.info(`Adopted camera ${cameraConfig.name} (${externalId})`)\n return device\n }\n\n private async persistAdoptedCamera(cam: OnvifCameraConfig): Promise<void> {\n const storage = this.ctx.storage\n if (!storage.structured) return\n\n try {\n const existing = await storage.structured.query('adopted-cameras', {\n where: { id: cam.id },\n limit: 1,\n })\n\n if (existing.length === 0) {\n await storage.structured.insert({\n collection: 'adopted-cameras',\n id: cam.id,\n data: { ...cam },\n })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn(`Failed to persist adopted camera ${cam.id}: ${message}`)\n }\n }\n\n getDevices(): IDevice[] {\n return [...this.devices]\n }\n\n getDeviceConfigSchema() {\n return {\n id: 'string',\n name: 'string',\n host: 'string (IP or hostname)',\n port: 'number (default: 80)',\n username: 'string (optional)',\n password: 'string (optional)',\n rtspUrl: 'string (optional, override ONVIF stream URI)',\n }\n }\n\n subscribeLiveEvents(_callback: (event: LiveEvent) => void): () => void {\n // ONVIF events via pipeline — no native event subscription here\n return () => {}\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n CapabilityProviderMap,\n ConfigUISchema,\n IConfigurable,\n} from '@camstack/types'\nimport { OnvifProvider } from './onvif-provider'\nimport type { OnvifProviderConfig } from './onvif-types'\n\nexport class OnvifProviderAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'provider-onvif',\n name: 'ONVIF Camera Provider',\n version: '0.1.0',\n description: 'Discovery automatica di camere ONVIF sulla rete locale',\n capabilities: ['device-provider'],\n }\n\n private provider: OnvifProvider | null = null\n\n async initialize(context: AddonContext): Promise<void> {\n const config = context.addonConfig as unknown as OnvifProviderConfig\n\n const providerConfig: OnvifProviderConfig = {\n id: config.id ?? 'onvif-default',\n name: config.name ?? 'ONVIF Cameras',\n discovery: config.discovery,\n cameras: config.cameras,\n defaultUsername: config.defaultUsername,\n defaultPassword: config.defaultPassword,\n }\n\n this.provider = new OnvifProvider(providerConfig, {\n id: context.id,\n logger: context.logger,\n eventBus: context.eventBus,\n storage: context.storage,\n config: context.config,\n })\n\n context.logger.info('ONVIF provider addon initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.provider?.stop()\n this.provider = null\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'device-provider' && this.provider) {\n return this.provider as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'discovery',\n title: 'ONVIF Discovery',\n description: 'Auto-discover ONVIF cameras on the local network',\n columns: 2,\n fields: [\n { type: 'boolean', key: 'discovery.enabled', label: 'Enable Auto-Discovery' },\n { type: 'number', key: 'discovery.timeout', label: 'Discovery Timeout', unit: 'ms', min: 1000, max: 30000, step: 1000 },\n ],\n },\n {\n id: 'credentials',\n title: 'Default Credentials',\n description: 'Default credentials for discovered cameras',\n columns: 2,\n fields: [\n { type: 'text', key: 'defaultUsername', label: 'Default Username' },\n { type: 'password', key: 'defaultPassword', label: 'Default Password', showToggle: true },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return {}\n }\n\n async onConfigChange(_config: Record<string, unknown>): Promise<void> {\n // Restart provider with new config\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-onvif",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "ONVIF camera device provider addon for CamStack",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"camstack",
|
|
7
|
+
"addon",
|
|
8
|
+
"camstack-addon",
|
|
9
|
+
"onvif",
|
|
10
|
+
"provider",
|
|
11
|
+
"camera",
|
|
12
|
+
"ip-camera"
|
|
13
|
+
],
|
|
6
14
|
"license": "MIT",
|
|
7
15
|
"repository": {
|
|
8
16
|
"type": "git",
|
|
@@ -12,21 +20,36 @@
|
|
|
12
20
|
"module": "./dist/index.mjs",
|
|
13
21
|
"types": "./dist/index.d.ts",
|
|
14
22
|
"exports": {
|
|
15
|
-
".": {
|
|
23
|
+
".": {
|
|
24
|
+
"import": "./dist/index.mjs",
|
|
25
|
+
"require": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
16
29
|
},
|
|
17
30
|
"camstack": {
|
|
31
|
+
"displayName": "ONVIF Provider",
|
|
18
32
|
"addons": [
|
|
19
33
|
{
|
|
20
34
|
"id": "provider-onvif",
|
|
21
35
|
"entry": "./dist/addon.js",
|
|
22
36
|
"slot": "provider",
|
|
37
|
+
"icon": "assets/icon.svg",
|
|
38
|
+
"color": "#06b6d4",
|
|
39
|
+
"instanceMode": "unique",
|
|
23
40
|
"capabilities": [
|
|
24
|
-
{
|
|
41
|
+
{
|
|
42
|
+
"name": "device-provider",
|
|
43
|
+
"mode": "collection"
|
|
44
|
+
}
|
|
25
45
|
]
|
|
26
46
|
}
|
|
27
47
|
]
|
|
28
48
|
},
|
|
29
|
-
"files": [
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"assets"
|
|
52
|
+
],
|
|
30
53
|
"scripts": {
|
|
31
54
|
"build": "tsup",
|
|
32
55
|
"dev": "tsup --watch",
|