Merge branch 'main' of github.com:koush/scrypted into main

This commit is contained in:
Koushik Dutta
2021-11-17 22:53:35 -08:00
2 changed files with 76 additions and 12 deletions

View File

@@ -17,8 +17,7 @@
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.0.93",
"version": "0.0.121",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -38,7 +37,10 @@
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"stringify-object": "^3.3.0",
"tmp": "^0.2.1",
"ts-loader": "^9.2.6",
"typedoc": "^0.22.8",
"typescript-json-schema": "^0.50.1",
"webpack": "^5.59.0"
},
@@ -49,6 +51,10 @@
"scrypted-package-json": "bin/scrypted-package-json.js",
"scrypted-readme": "bin/scrypted-readme.js",
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/stringify-object": "^4.0.0",
"ts-node": "^10.4.0"
}
},
"node_modules/@scrypted/sdk": {
@@ -56,9 +62,9 @@
"link": true
},
"node_modules/@types/node": {
"version": "16.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
"version": "16.11.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
"integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
"dev": true
},
"node_modules/axios": {
@@ -101,6 +107,7 @@
"@babel/plugin-transform-typescript": "^7.15.8",
"@babel/preset-typescript": "^7.15.0",
"@types/node": "^16.11.1",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"babel-loader": "^8.2.3",
@@ -109,15 +116,19 @@
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"stringify-object": "^3.3.0",
"tmp": "^0.2.1",
"ts-loader": "^9.2.6",
"ts-node": "^10.4.0",
"typedoc": "^0.22.8",
"typescript-json-schema": "^0.50.1",
"webpack": "^5.59.0"
}
},
"@types/node": {
"version": "16.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
"version": "16.11.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
"integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
"dev": true
},
"axios": {

View File

@@ -1,11 +1,14 @@
import sdk, { ScryptedDeviceBase, DeviceProvider, Settings, Setting, ScryptedDeviceType, VideoCamera, MediaObject, Device, ScryptedInterface, Camera, MediaStreamOptions, PictureOptions } from "@scrypted/sdk";
import sdk, { ScryptedDeviceBase, DeviceProvider, HttpRequest, HttpRequestHandler, HttpResponse, Settings, Setting, ScryptedDeviceType, VideoCamera, MediaObject, Device, MotionSensor, ScryptedInterface, Camera, MediaStreamOptions, PictureOptions } from "@scrypted/sdk";
import { createInstanceableProviderPlugin, enableInstanceableProviderMode, isInstanceableProviderModeEnabled } from '../../../common/src/provider-plugin';
import { recommendRebroadcast } from "../../rtsp/src/recommend";
import {SynologyApiClient, SynologyCameraStream, SynologyCamera} from "./api/synology-api-client";
const { log, deviceManager, mediaManager } = sdk;
class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Settings, VideoCamera {
class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, HttpRequestHandler, MotionSensor, Settings, VideoCamera {
private static readonly DefaultSensorTimeoutSecs: number = 30;
private motionTimeout?: NodeJS.Timeout;
private provider: SynologySurveillanceStation;
private streams: SynologyCameraStream[];
@@ -13,6 +16,7 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Setting
super(nativeId);
this.provider = provider;
this.motionDetected = false;
this.streams = SynologyCameraDevice.identifyStreams(camera);
}
@@ -38,6 +42,7 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Setting
public async getSettings(): Promise<Setting[]> {
const vsos = await this.getVideoStreamOptions();
const defaultStream = this.getDefaultStream(vsos);
return [
{
title: 'Default Stream',
@@ -45,6 +50,20 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Setting
value: defaultStream?.name,
choices: vsos.map(vso => vso.name),
description: 'The default stream to use when not specified',
},
{
title: 'Motion Sensor Timeout',
key: 'sensorTimeout',
type: 'integer',
value: this.storage.getItem('sensorTimeout') || SynologyCameraDevice.DefaultSensorTimeoutSecs,
description: 'Time to wait in seconds before clearing the motion detected state.',
},
{
title: 'Motion Sensor Webhook',
type: 'string',
readonly: true,
value: await this.getMotionDetectedWebhookUrl(),
description: 'To get motion alerts, create an alert rule in Surveillance Station that POSTs to this webhook URL upon motion detected.',
}
];
}
@@ -61,6 +80,17 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Setting
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
}
getSensorTimeout() {
return (parseInt(this.storage.getItem('sensorTimeout')) || SynologyCameraDevice.DefaultSensorTimeoutSecs) * 1000;
}
resetMotionTimeout() {
clearTimeout(this.motionTimeout);
this.motionTimeout = setTimeout(() => {
this.motionDetected = false;
}, this.getSensorTimeout());
}
private async getSnapshot(options?: PictureOptions): Promise<Buffer> {
const data = await this.provider.api.getCameraSnapshot(this.nativeId);
@@ -83,6 +113,7 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Setting
throw new Error(`Unable to locate RTSP stream for camera ${this.nativeId}`);
return mediaManager.createFFmpegMediaObject({
url: liveViewPaths[0].rtspPath,
inputArguments: [
"-rtsp_transport",
"tcp",
@@ -127,6 +158,26 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, Setting
return;
}
public async onRequest(request: HttpRequest, response: HttpResponse): Promise<void> {
if (request.url.endsWith('/motionDetected')) {
this.motionDetected = true;
this.resetMotionTimeout();
response.send('Success', {
code: 200,
});
} else {
response.send('Unsupported operation', {
code: 400,
});
}
}
private async getMotionDetectedWebhookUrl(): Promise<string> {
const webhookUrl = await sdk.endpointManager.getInsecurePublicLocalEndpoint(this.nativeId);
return `${webhookUrl}motionDetected`;
}
/**
* Identify and return available streams on the provided camera.
*/
@@ -207,11 +258,13 @@ class SynologySurveillanceStation extends ScryptedDeviceBase implements Settings
manufacturer: camera.vendor,
model: camera.model,
firmware: camera.firmware,
serialNumber: '' + camera.id
serialNumber: `Camera-${camera.id}`,
},
interfaces: [
ScryptedInterface.Settings,
ScryptedInterface.Camera,
ScryptedInterface.HttpRequestHandler,
ScryptedInterface.MotionSensor,
ScryptedInterface.Settings,
ScryptedInterface.VideoCamera,
],
type: ScryptedDeviceType.Camera