Compare commits

..

3 Commits

Author SHA1 Message Date
Koushik Dutta
801bd46730 server: default auth should be last available option 2024-01-31 12:10:25 -08:00
Koushik Dutta
e5a764d82f reolink: use onvif events on doorbell 2024-01-31 12:10:08 -08:00
Koushik Dutta
7c9cd9f112 postrelease 2024-01-30 10:03:47 -08:00
7 changed files with 71 additions and 32 deletions

View File

@@ -103,6 +103,8 @@ export class OnvifCameraAPI {
const dataValue = event.message.message.data.simpleItem.$.Value;
const eventTopic = stripNamespaces(event.topic._);
ret.emit('onvifEvent', eventTopic, dataValue);
if (eventTopic.includes('MotionAlarm')) {
// ret.emit('event', OnvifEvent.MotionBuggy);
if (dataValue)

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/reolink",
"version": "0.0.58",
"version": "0.0.59",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/reolink",
"version": "0.0.58",
"version": "0.0.59",
"license": "Apache",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/reolink",
"version": "0.0.58",
"version": "0.0.59",
"description": "Reolink Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -3,7 +3,7 @@ import sdk, { Camera, DeviceCreatorSettings, DeviceInformation, Intercom, MediaO
import { StorageSettings } from '@scrypted/sdk/storage-settings';
import { EventEmitter } from "stream";
import { Destroyable, RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
import { OnvifCameraAPI, connectCameraAPI } from './onvif-api';
import { OnvifCameraAPI, OnvifEvent, connectCameraAPI } from './onvif-api';
import { listenEvents } from './onvif-events';
import { OnvifIntercom } from './onvif-intercom';
import { AIState, DevInfo, Enc, ReolinkCameraClient } from './reolink-api';
@@ -49,6 +49,10 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, Reboot, Intercom,
await this.updateDevice();
this.updatePtzCaps();
},
},
doorbellUseOnvifDetections: {
hide: true,
defaultValue: true,
}
});
@@ -80,6 +84,12 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, Reboot, Intercom,
}
async getObjectTypes(): Promise<ObjectDetectionTypes> {
if (this.storageSettings.values.doorbell && this.storageSettings.values.doorbellUseOnvifDetections) {
return {
classes: ['person'],
};
}
try {
const ai: AIState = this.storageSettings.values.hasObjectDetector[0]?.value;
const classes: string[] = [];
@@ -228,9 +238,35 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, Reboot, Intercom,
if (this.storageSettings.values.doorbell) {
const ret = await listenEvents(this, await this.createOnvifClient(), this.storageSettings.values.motionTimeout * 1000);
if (!this.storageSettings.values.doorbellUseOnvifDetections) {
startAI(ret, ret.triggerMotion);
}
else {
ret.on('onvifEvent', (eventTopic: string, dataValue: any) => {
if (eventTopic.includes('PeopleDetect')) {
if (dataValue) {
ret.emit('event', OnvifEvent.MotionStart);
const od: ObjectsDetected = {
timestamp: Date.now(),
detections: [
{
className: 'person',
score: 1,
}
],
};
sdk.deviceManager.onDeviceEvent(this.nativeId, ScryptedInterface.ObjectDetector, od);
}
else {
ret.emit('event', OnvifEvent.MotionStop);
}
}
});
}
ret.on('close', () => killed = true);
ret.on('error', () => killed = true);
startAI(ret, ret.triggerMotion);
return ret;
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/server",
"version": "0.91.0",
"version": "0.93.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/server",
"version": "0.91.0",
"version": "0.93.0",
"license": "ISC",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.11",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/server",
"version": "0.92.0",
"version": "0.93.0",
"description": "",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.11",

View File

@@ -220,14 +220,6 @@ async function start(mainFilename: string, options?: {
}
app.use(async (req, res, next) => {
const defaultAuthentication = getDefaultAuthentication(req);
if (defaultAuthentication) {
res.locals.username = defaultAuthentication._id;
res.locals.aclId = defaultAuthentication.aclId;
next();
return;
}
// the remote address may be ipv6 prefixed so use a fuzzy match.
// eg ::ffff:192.168.2.124
if (process.env.SCRYPTED_ADMIN_USERNAME
@@ -307,6 +299,15 @@ async function start(mainFilename: string, options?: {
else if (req.query['scryptedToken']) {
checkToken(req.query.scryptedToken.toString());
}
if (!res.locals.username) {
const defaultAuthentication = getDefaultAuthentication(req);
if (defaultAuthentication) {
res.locals.username = defaultAuthentication._id;
res.locals.aclId = defaultAuthentication.aclId;
}
}
next();
});
@@ -637,22 +638,6 @@ async function start(mainFilename: string, options?: {
return;
}
// env based anon user login
const defaultAuthentication = getDefaultAuthentication(req);
if (defaultAuthentication) {
const userToken = new UserToken(defaultAuthentication._id, defaultAuthentication.aclId, Date.now());
res.send({
...createTokens(userToken),
expiration: ONE_DAY_MILLISECONDS,
username: defaultAuthentication,
// TODO: do not return the token from a short term auth mechanism?
token: defaultAuthentication?.token,
...alternateAddresses,
hostname,
});
return;
}
// basic auth
if (req.protocol === 'https' && req.headers.authorization) {
const username = await new Promise(resolve => {
@@ -697,6 +682,22 @@ async function start(mainFilename: string, options?: {
})
}
catch (e) {
// env based anon user login
const defaultAuthentication = getDefaultAuthentication(req);
if (defaultAuthentication) {
const userToken = new UserToken(defaultAuthentication._id, defaultAuthentication.aclId, Date.now());
res.send({
...createTokens(userToken),
expiration: ONE_DAY_MILLISECONDS,
username: defaultAuthentication,
// TODO: do not return the token from a short term auth mechanism?
token: defaultAuthentication?.token,
...alternateAddresses,
hostname,
});
return;
}
res.send({
error: e?.message || 'Unknown Error.',
hasLogin,