From 16cf72954f44ec978bb85fa186dcb0c94e558a2d Mon Sep 17 00:00:00 2001 From: JDierkse Date: Thu, 14 Jul 2022 10:18:31 +0200 Subject: [PATCH] Add CameraAccessory --- cameraAccessory.ts | 113 +++++++++++++++++++++++++++++++++++++++++++++ platform.ts | 23 +++++++-- 2 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 cameraAccessory.ts diff --git a/cameraAccessory.ts b/cameraAccessory.ts new file mode 100644 index 0000000..75d977e --- /dev/null +++ b/cameraAccessory.ts @@ -0,0 +1,113 @@ +import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge' + +import { accessory } from './accessory' +import { device } from './device' +import { httpRequest, response } from './httpPromise' +import { domoticaPlatform } from './platform' + +export class cameraAccessory extends accessory { + private service: Service + + private state = { + Motion: false + } + + static async discoverDevices(platform: domoticaPlatform): Promise { + return new Promise((resolve, reject) => { + let cameraDevices: device[] = [] + + httpRequest("http://" + platform.config.hostname + ':' + platform.config.port + '/API/inventory/camera') + .then((response) => { + let devices = JSON.parse(response.body) + + for (const device of devices) { + if (device.enabled == "true" && + device.brand == "RTSP" && + device.motiondetect == "true") { + let object: device = { + type: "Camera", + typeId: device.id, + uniqueId: "Camera." + device.id, + deviceName: device.name, + switchable: "false", + dimmable: "false", + detailedType: device.brand + } + cameraDevices.push(object) + } + } + + resolve(cameraDevices) + }) + .catch((error) => { + reject('cameraAccessory::discoverDevices Error ->' + error) + }) + }) + } + + constructor( + private readonly platform: domoticaPlatform, + private readonly accessory: PlatformAccessory, + ) { + super("Camera", accessory.context.device.typeId) + this.accessory.getService(this.platform.Service.AccessoryInformation)! + .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Camera') + .setCharacteristic(this.platform.Characteristic.Model, 'ONVIF') + .setCharacteristic(this.platform.Characteristic.SerialNumber, '07000' + accessory.context.device.typeId) + + this.service = this.accessory.getService(this.platform.Service.MotionSensor) || this.accessory.addService(this.platform.Service.MotionSensor) + + this.service.getCharacteristic(this.platform.Characteristic.MotionDetected) + .onGet(this.getState.bind(this)); + + this.setName(accessory.context.device.deviceName) + this.update() + } + + setName(name) { + this.service.setCharacteristic(this.platform.Characteristic.Name, name) + } + + setValue(key, value) { + if (key == "state" && value != "") { + if (value == "On") { + this.state.Motion = true + } else { + this.state.Motion = false + } + this.service.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.state.Motion) + } + } + + update() { + const data = JSON.stringify([{ + type: 'camera', + query: 'state' + }]) + + httpRequest("http://" + this.platform.config.hostname + ':' + this.platform.config.port + '/API/Status', data) + .then((response) => { + const devices = JSON.parse(response.body) + + for (const device of devices.camera) { + if (device.id == this.accessory.context.device.typeId) { + if (device.motionstate == 'absent') { + this.state.Motion = false + } else { // present + this.state.Motion = true + } + return this.state.Motion + this.service.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.state.Motion) + break + } + } + }) + .catch((error) => { + this.platform.log.debug('cameraAccessory::update Error ->' + error) + }) + } + + getState(): CharacteristicValue { + return this.state.Motion + } +} diff --git a/platform.ts b/platform.ts index 418fbbe..937d107 100644 --- a/platform.ts +++ b/platform.ts @@ -10,6 +10,7 @@ import { powerSwitchAccessory } from './powerSwitchAccessory' import { environmentSensorAccessory } from './environmentSensorAccessory' import { doorWindowSensorAccessory } from './doorWindowSensorAccessory' import { motionSensorAccessory } from './motionSensorAccessory' +import { cameraAccessory } from './cameraAccessory' import { httpServer } from './httpServer' export class domoticaPlatform implements DynamicPlatformPlugin { @@ -19,7 +20,7 @@ export class domoticaPlatform implements DynamicPlatformPlugin { public readonly accessories: accessory[] = [] public readonly cachedAccessories: PlatformAccessory[] = [] public readonly presentAccessories: PlatformAccessory[] = [] - + private readonly discoveries: String[] = [] private readonly completedDiscoveries: String[] = [] @@ -100,6 +101,16 @@ export class domoticaPlatform implements DynamicPlatformPlugin { .catch((error) => { this.log.debug('motionSensorAccessory.discoverDevices Error ->' + error) }) + + this.discoveryStarted('cameraAccessory') + cameraAccessory.discoverDevices(this) + .then((devices) => { + this.processDiscoveredDevices(devices) + this.discoveryCompleted('cameraAccessory') + }) + .catch((error) => { + this.log.debug('cameraAccessory.discoverDevices Error ->' + error) + }) } processDiscoveredDevices(domoticaDevices: device[]) { @@ -130,6 +141,8 @@ export class domoticaPlatform implements DynamicPlatformPlugin { this.accessories.push(new doorWindowSensorAccessory(this, existingAccessory)) } else if (existingAccessory.context.device.type == 'MotionSensor') { this.accessories.push(new motionSensorAccessory(this, existingAccessory)) + } else if (existingAccessory.context.device.type == 'Camera') { + this.accessories.push(new cameraAccessory(this, existingAccessory)) } } else { this.log.info('+ ' + device.type + ': ' + device.deviceName) @@ -149,6 +162,8 @@ export class domoticaPlatform implements DynamicPlatformPlugin { this.accessories.push(new doorWindowSensorAccessory(this, accessory)) } else if (accessory.context.device.type == 'MotionSensor') { this.accessories.push(new motionSensorAccessory(this, accessory)) + } else if (accessory.context.device.type == 'Camera') { + this.accessories.push(new cameraAccessory(this, accessory)) } this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]) @@ -162,14 +177,14 @@ export class domoticaPlatform implements DynamicPlatformPlugin { discoveryCompleted(deviceType) { this.completedDiscoveries.push(deviceType) - + if (this.completedDiscoveries.length == this.discoveries.length) { this.cleanupRemovedDevices() } - + //setInterval(this.updateAccessories.bind(this), 60 * 1000); // Poll every minute } - + updateAccessories() { for (const accessory of this.accessories) { accessory.update()