cameras: fix event timeout, add debug event log

This commit is contained in:
Koushik Dutta
2022-08-22 09:02:27 -07:00
parent 516a748194
commit 032fec4eb6
12 changed files with 60 additions and 38 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/amcrest",
"version": "0.0.105",
"version": "0.0.106",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/amcrest",
"version": "0.0.105",
"version": "0.0.106",
"hasInstallScript": true,
"license": "Apache",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/amcrest",
"version": "0.0.105",
"version": "0.0.106",
"description": "Amcrest Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.96",
"version": "0.0.97",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/hikvision",
"version": "0.0.96",
"version": "0.0.97",
"hasInstallScript": true,
"license": "Apache",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.96",
"version": "0.0.97",
"description": "HikVision Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -111,7 +111,7 @@ export class HikVisionCameraAPI {
if (!this.listenerPromise) {
this.listenerPromise = new Promise(async (resolve, reject) => {
const url = `http://${this.ip}/ISAPI/Event/notification/alertStream`;
this.console.log('listener url', url);
// this.console.log('listener url', url);
const response = await this.digestAuth.request({
method: "GET",
@@ -123,11 +123,11 @@ export class HikVisionCameraAPI {
stream.on('data', (buffer: Buffer) => {
const data = buffer.toString();
// this.console.log(data);
for (const event of Object.values(HikVisionCameraEvent)) {
if (data.indexOf(event) !== -1) {
const cameraNumber = data.match(/<channelID>(.*?)</)?.[1] || data.match(/<dynChannelID>(.*?)</)?.[1];
stream.emit('event', event, cameraNumber);
const inactive = data.indexOf('<eventState>inactive</eventState>') !== -1;
stream.emit('event', event, cameraNumber, inactive);
}
}
});

View File

@@ -1,4 +1,4 @@
import sdk, { MediaObject, Camera, ScryptedInterface } from "@scrypted/sdk";
import sdk, { MediaObject, Camera, ScryptedInterface, Setting } from "@scrypted/sdk";
import { EventEmitter } from "stream";
import { HikVisionCameraAPI } from "./hikvision-camera-api";
import { Destroyable, UrlMediaStreamOptions, RtspProvider, RtspSmartCamera } from "../../rtsp/src/rtsp";
@@ -36,7 +36,7 @@ class HikVisionCamera extends RtspSmartCamera implements Camera {
let ignoreCameraNumber: boolean;
events.on('event', async (event: HikVisionCameraEvent, cameraNumber: string) => {
events.on('event', async (event: HikVisionCameraEvent, cameraNumber: string, inactive: boolean) => {
if (event === HikVisionCameraEvent.MotionDetected
|| event === HikVisionCameraEvent.LineDetection
|| event === HikVisionCameraEvent.FieldDetection) {
@@ -75,7 +75,7 @@ class HikVisionCamera extends RtspSmartCamera implements Camera {
// this.console.error('### Detected motion, camera: ', cameraNumber);
this.motionDetected = true;
clearTimeout(motionTimeout);
motionTimeout = setTimeout(() => this.motionDetected = false, 30000);
motionTimeout = setTimeout(() => this.motionDetected = false, inactive ? 5000 : 30000);
}
})
@@ -97,9 +97,26 @@ class HikVisionCamera extends RtspSmartCamera implements Camera {
return mediaManager.createMediaObject(await api.jpegSnapshot(this.getRtspChannel()), 'image/jpeg');
}
async getUrlSettings() {
async getRtspUrlSettings(): Promise<Setting[]> {
const ret = await super.getRtspUrlSettings();
ret.push(
{
group: 'Advanced',
key: 'rtspUrlParams',
title: 'RTSP URL Parameters Override',
description: "Optional: Override the RTSP URL parameters. E.g.: ?transportmode=unicast",
placeholder: this.getRtspUrlParams(),
value: this.storage.getItem('rtspUrlParams'),
},
);
return ret;
}
async getUrlSettings(): Promise<Setting[]> {
return [
{
group: 'Advanced',
key: 'rtspChannel',
title: 'Channel Number',
description: "Optional: The channel number to use for snapshots. E.g., 101, 201, etc. The camera portion, e.g., 1, 2, etc, will be used to construct the RTSP stream.",
@@ -107,13 +124,6 @@ class HikVisionCamera extends RtspSmartCamera implements Camera {
value: this.storage.getItem('rtspChannel'),
},
...await super.getUrlSettings(),
{
key: 'rtspUrlParams',
title: 'RTSP URL Parameters Override',
description: "Optional: Override the RTSP URL parameters. E.g.: ?transportmode=unicast",
placeholder: this.getRtspUrlParams(),
value: this.storage.getItem('rtspUrlParams'),
},
]
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/onvif",
"version": "0.0.93",
"version": "0.0.94",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/onvif",
"version": "0.0.93",
"version": "0.0.94",
"license": "Apache",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/onvif",
"version": "0.0.93",
"version": "0.0.94",
"description": "ONVIF Camera Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -1,9 +1,9 @@
import sdk, { MediaObject, ScryptedInterface, Setting, ScryptedDeviceType, PictureOptions, VideoCamera, DeviceDiscovery, ObjectDetector, ObjectDetectionTypes, ObjectsDetected, Settings, Intercom, SettingValue } from "@scrypted/sdk";
import { EventEmitter, Stream } from "stream";
import { RtspSmartCamera, RtspProvider, Destroyable, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
import { connectCameraAPI, OnvifCameraAPI, OnvifEvent } from "./onvif-api";
import xml2js from 'xml2js';
import sdk, { DeviceDiscovery, Intercom, MediaObject, ObjectDetectionTypes, ObjectDetector, ObjectsDetected, PictureOptions, ScryptedDeviceType, ScryptedInterface, Setting, Settings, SettingValue, VideoCamera } from "@scrypted/sdk";
import onvif from 'onvif';
import { Stream } from "stream";
import xml2js from 'xml2js';
import { Destroyable, RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
import { connectCameraAPI, OnvifCameraAPI, OnvifEvent } from "./onvif-api";
import { OnvifIntercom } from "./onvif-intercom";
const { mediaManager, systemManager, deviceManager } = sdk;
@@ -224,7 +224,7 @@ class OnvifCamera extends RtspSmartCamera implements ObjectDetector, Intercom {
}
createClient() {
return connectCameraAPI(this.getHttpAddress(), this.getUsername(), this.getPassword(), this.console, this.storage.getItem('onvifDoorbellEvent'), !!this.storage.getItem('debug'));
return connectCameraAPI(this.getHttpAddress(), this.getUsername(), this.getPassword(), this.console, this.storage.getItem('onvifDoorbellEvent'));
}
async getClient() {

View File

@@ -61,7 +61,7 @@ export class OnvifCameraAPI {
digestAuth: AxiosDigestAuth;
detections: Map<string, string>;
constructor(public cam: any, username: string, password: string, public console: Console, binaryStateEvent: string, public debug?: boolean) {
constructor(public cam: any, username: string, password: string, public console: Console, binaryStateEvent: string) {
this.binaryStateEvent = binaryStateEvent
this.digestAuth = new AxiosDigestAuth({
username,
@@ -74,11 +74,6 @@ export class OnvifCameraAPI {
this.cam.on('event', (event: any, xml: string) => {
const eventTopic = stripNamespaces(event.topic._)
if (this.debug) {
this.console.log('event', eventTopic);
this.console.log(JSON.stringify(event, null, 2));
this.console.log(xml);
}
if (event.message.message.data && event.message.message.data.simpleItem) {
const dataValue = event.message.message.data.simpleItem.$.Value;
@@ -271,7 +266,7 @@ export class OnvifCameraAPI {
}
}
export async function connectCameraAPI(ipAndPort: string, username: string, password: string, console: Console, binaryStateEvent: string, debugLog?: boolean) {
export async function connectCameraAPI(ipAndPort: string, username: string, password: string, console: Console, binaryStateEvent: string) {
const split = ipAndPort.split(':');
const [hostname, port] = split;
const cam = await promisify(cb => {
@@ -282,5 +277,5 @@ export async function connectCameraAPI(ipAndPort: string, username: string, pass
port,
}, (err: Error) => cb(err, cam));
});
return new OnvifCameraAPI(cam, username, password, console, binaryStateEvent, debugLog);
return new OnvifCameraAPI(cam, username, password, console, binaryStateEvent);
}

View File

@@ -40,6 +40,7 @@ function addSupportedCodec(ffmpegCodec: string, sdpName: string) {
addSupportedCodec('pcm_mulaw', 'PCMU');
addSupportedCodec('pcm_alaw', 'PCMA');
addSupportedCodec('pcm_s16be', 'L16');
addSupportedCodec('adpcm_g726', 'G726');
addSupportedCodec('aac', 'MPEG4-GENERIC');
interface CodecMatch {
@@ -78,6 +79,7 @@ export class OnvifIntercom implements Intercom {
url.username = username;
url.password = password;
this.intercomClient = new RtspClient(url.toString());
this.intercomClient.console = this.camera.console;
await this.intercomClient.options();
const Require = 'www.onvif.org/ver20/backchannel';

View File

@@ -199,7 +199,11 @@ export abstract class RtspSmartCamera extends RtspCamera {
}
resetActivityTimeout();
listener.on('data', resetActivityTimeout);
listener.on('data', (data) => {
if (this.storage.getItem('debug') === 'true')
this.console.log('debug event:\n', data.toString());
resetActivityTimeout();
});
listener.on('close', () => {
this.console.error('listen loop closed, restarting listener.');
@@ -260,6 +264,17 @@ export abstract class RtspSmartCamera extends RtspCamera {
);
}
ret.push(
{
group: 'Advanced',
key: 'debug',
title: 'Debug Events',
description: "Log all events to the console. This will be very noisy and should not be left enabled.",
value: !!this.storage.getItem('debug'),
type: 'boolean',
}
)
return ret;
}