UNPKG

homebridge-hikvision-local

Version:

Homebridge plugin that connects to your HikVision DVR via a local connection and exposes your cameras in Homebridge. The plugin is heavily based on excellent [homebridge-camera-ffmpeg](https://github.com/Sunoo/homebridge-camera-ffmpeg) and the various hom

141 lines 7.46 kB
// We borrow, rather cheekly from the homebridge-camera-ffmpeg plugin. // TODO: probably rethink and do something like https://github.com/homebridge/homebridge-examples/tree/master/bridged-camera-example-typescript. import { Logger } from '@homebridge-plugins/homebridge-camera-ffmpeg/dist/logger.js'; import { StreamingDelegate } from '@homebridge-plugins/homebridge-camera-ffmpeg/dist/streamingDelegate.js'; export class HikVisionCamera { constructor(log, homebridgeApi, accessory, config) { this.motionDetected = false; this.log = log; this.homebridgeApi = homebridgeApi; this.accessory = accessory; this.displayName = this.accessory.displayName; this.UUID = accessory.UUID; this.config = config; this.configure(this.accessory); } getService(...args) { return this.accessory.getService(...args); } configureController(...args) { return this.accessory.configureController(...args); } addService(...args) { return this.accessory.addService(...args); } removeService(...args) { return this.accessory.removeService(...args); } on(...args) { this.accessory.on(...args); } getServiceByUUIDAndSubType(uuid, subType) { return undefined; } configure(accessory) { this.log.info( // eslint-disable-next-line max-len `Configuring ${(this.config.doorbells && this.config.doorbells.includes(accessory.displayName) ? 'doorbell' : 'camera')} accessory: ${accessory.displayName} - ${JSON.stringify(accessory.context)}`); accessory.on('identify', () => { this.log(`${accessory.displayName} identified!`); }); let motionSensor = accessory.getService(this.homebridgeApi.hap.Service.MotionSensor); if (motionSensor) { this.log.info('Re-creating motion sensor'); accessory.removeService(motionSensor); } else { // this.log.warn('There was no motion sensor set up!'); } motionSensor = new this.homebridgeApi.hap.Service.MotionSensor(accessory.displayName); accessory.addService(motionSensor); if (this.config.doorbells && this.config.doorbells.includes(accessory.displayName)) { this.log.info(`Creating Doorbell Trigger: ${accessory.displayName} Doorbell Trigger`); const doorbellService = new this.homebridgeApi.hap.Service.Doorbell(accessory.displayName + ' Doorbell'); accessory.addService(doorbellService); const switchService = new this.homebridgeApi.hap.Service.Switch(accessory.displayName + ' Doorbell Trigger', 'DoorbellTrigger'); switchService.getCharacteristic(this.homebridgeApi.hap.Characteristic.On) .on('set', (state, callback) => { this.log.info(`Doorbell trigger for ${accessory.displayName} - ${state}`); if (state) { doorbellService.getCharacteristic(this.homebridgeApi.hap.Characteristic.ProgrammableSwitchEvent).setValue(this.homebridgeApi.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS); setTimeout(() => { switchService.getCharacteristic(this.homebridgeApi.hap.Characteristic.On).updateValue(false); }, 5000); } callback(null); }); accessory.addService(switchService); } // doorbell.updateCharacteristic(hap.Characteristic.ProgrammableSwitchEvent, hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS); const channelId = accessory.context.channelId; const cameraConfig = { name: accessory.displayName, videoConfig: { source: `-rtsp_transport tcp -i rtsp://${accessory.context.username}:${accessory.context.password}@${accessory.context.host}/Streaming/Channels/${channelId}01`, stillImageSource: `-i http${accessory.context.secure ? 's' : ''}://${accessory.context.username}:${accessory.context.password}@${accessory.context.host}/ISAPI/Streaming/channels/${channelId}01/picture?videoResolutionWidth=720`, maxFPS: (accessory.context.maxFPS ? accessory.context.maxFPS : 30), maxBitrate: (accessory.context.maxBitrate ? accessory.context.maxBitrate : 16384), maxWidth: (accessory.context.maxWidth ? accessory.context.maxWidth : 1920), maxHeight: (accessory.context.maxHeight ? accessory.context.maxHeight : 1080), vcodec: 'libx264', audio: accessory.context.hasAudio, debug: Boolean(accessory.context.debugFfmpeg), }, }; const cameraLogger = new Logger(this.log); // Use the homebridge-camera-ffmpeg StreamingDelegate. const streamingDelegate = new StreamingDelegate(cameraLogger, cameraConfig, this.homebridgeApi, this.homebridgeApi.hap, accessory); const cameraControllerOptions = { cameraStreamCount: 5, // HomeKit requires at least 2 streams, but 1 is also just fine delegate: streamingDelegate, streamingOptions: { supportedCryptoSuites: [ 0 /* this.homebridgeApi.hap.SRTPCryptoSuites.AES_CM_128_HMAC_SHA1_80 */, ], video: { resolutions: [ // TODO: put in the max framerates & resolutions from the camera config. [320, 180, 30], [320, 240, 15], // Apple Watch requires this configuration [320, 240, 30], [480, 270, 30], [480, 360, 30], [640, 360, 30], [640, 480, 30], [1280, 720, 30], [1280, 960, 30], [1920, 1080, 30], [1600, 1200, 30], ], codec: { profiles: [ 0 /* this.homebridgeApi.hap.H264Profile.BASELINE */, 1 /* this.homebridgeApi.hap.H264Profile.MAIN */, 2 /* this.homebridgeApi.hap.H264Profile.HIGH */, ], levels: [ 0 /* this.homebridgeApi.hap.H264Level.LEVEL3_1 */, 1 /* this.homebridgeApi.hap.H264Level.LEVEL3_2 */, 2 /* this.homebridgeApi.hap.H264Level.LEVEL4_0 */, ], }, }, audio: { codecs: [ { type: "OPUS" /* AudioStreamingCodecType.OPUS */, samplerate: 24 /* AudioStreamingSamplerate.KHZ_24 */, }, { type: "AAC-eld" /* AudioStreamingCodecType.AAC_ELD */, samplerate: 16 /* AudioStreamingSamplerate.KHZ_16 */, }, ], }, }, }; const cameraController = new this.homebridgeApi.hap.CameraController(cameraControllerOptions, true); accessory.configureController(cameraController); } } //# sourceMappingURL=HikVisionCamera.js.map