homekit: fix missing opencv motion detector

This commit is contained in:
Koushik Dutta
2021-12-13 18:07:30 -08:00
parent 957f141284
commit 42f80fed1d
4 changed files with 145 additions and 29 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/homekit",
"version": "0.0.134",
"version": "0.0.135",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/homekit",
"version": "0.0.134",
"version": "0.0.135",
"dependencies": {
"hap-nodejs": "file:../../external/HAP-NodeJS",
"lodash": "^4.17.21",

View File

@@ -40,5 +40,5 @@
"@types/qrcode": "^1.4.1",
"@types/url-parse": "^1.4.3"
},
"version": "0.0.134"
"version": "0.0.135"
}

View File

@@ -143,7 +143,7 @@ export class CameraMixin extends SettingsMixinDeviceBase<any> implements Setting
type: 'device',
deviceFilter: 'interfaces.includes("MotionSensor")',
value: this.storage.getItem('linkedMotionSensor') || null,
placeholder: this.providedInterfaces.includes(ScryptedInterface.MotionSensor)
placeholder: this.interfaces.includes(ScryptedInterface.MotionSensor)
? 'Built-In Motion Sensor' : 'None',
description: "Link motion sensor used to trigger HomeKit Secure Video recordings.",
})
@@ -161,34 +161,33 @@ export class CameraMixin extends SettingsMixinDeviceBase<any> implements Setting
if (this.interfaces.includes(ScryptedInterface.ObjectDetector)) {
try {
const types = await realDevice.getObjectTypes();
const choices = types.people?.map(p => `Person: ${p.label}`) || [];
if (types.classes)
choices.push(...types.classes);
if (types.classes?.length) {
const value: string[] = [];
try {
value.push(...JSON.parse(this.storage.getItem('objectDetectionContactSensors')));
}
catch (e) {
}
const value: string[] = [];
try {
value.push(...JSON.parse(this.storage.getItem('objectDetectionContactSensors')));
}
catch (e) {
settings.push({
title: 'Object Detection Contact Sensors',
type: 'string',
choices: types.classes,
multiple: true,
key: 'objectDetectionContactSensors',
description: 'Create HomeKit contact sensors that detect specific people or objects.',
value,
});
settings.push({
title: 'Object Detection Contact Sensor Timeout',
type: 'number',
key: 'objectDetectionContactSensorTimeout',
description: 'Duration in seconds to keep the contact sensor open.',
value: this.storage.getItem('objectDetectionContactSensorTimeout') || defaultObjectDetectionContactSensorTimeout,
});
}
settings.push({
title: 'Object Detection Contact Sensors',
type: 'string',
choices,
multiple: true,
key: 'objectDetectionContactSensors',
description: 'Create HomeKit contact sensors that detect specific people or objects.',
value,
});
settings.push({
title: 'Object Detection Contact Sensor Timeout',
type: 'number',
key: 'objectDetectionContactSensorTimeout',
description: 'Duration in seconds to keep the contact sensor open.',
value: this.storage.getItem('objectDetectionContactSensorTimeout') || defaultObjectDetectionContactSensorTimeout,
});
}
catch (e) {
}

View File

@@ -0,0 +1,117 @@
import { Request, Response, Router } from 'express';
import bodyParser from 'body-parser';
import { HttpRequest } from '@scrypted/sdk/types';
import WebSocket, { Server as WebSocketServer } from "ws";
import { ServerResponse } from 'http';
export abstract class PluginHttp<T> {
wss = new WebSocketServer({ noServer: true });
constructor(public app: Router) {
app.all(['/endpoint/@:owner/:pkg/public/engine.io/*', '/endpoint/:pkg/public/engine.io/*'], (req, res) => {
this.endpointHandler(req, res, true, true, this.handleEngineIOEndpoint.bind(this))
});
app.all(['/endpoint/@:owner/:pkg/engine.io/*', '/endpoint/@:owner/:pkg/engine.io/*'], (req, res) => {
this.endpointHandler(req, res, false, true, this.handleEngineIOEndpoint.bind(this))
});
// stringify all http endpoints
app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], bodyParser.text() as any);
app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg/public', '/endpoint/:pkg/public/*'], (req, res) => {
this.endpointHandler(req, res, true, false, this.handleRequestEndpoint.bind(this))
});
app.all(['/endpoint/@:owner/:pkg', '/endpoint/@:owner/:pkg/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], (req, res) => {
this.endpointHandler(req, res, false, false, this.handleRequestEndpoint.bind(this))
});
}
abstract handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: T): Promise<void>;
abstract handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: T): Promise<void>;
abstract getEndpointPluginData(endpoint: string, isUpgrade: boolean, isEngineIOEndpoint: boolean): Promise<T>;
abstract handleWebSocket(endpoint: string, httpRequest: HttpRequest, ws: WebSocket, pluginData: T): Promise<void>;
async endpointHandler(req: Request, res: Response, isPublicEndpoint: boolean, isEngineIOEndpoint: boolean,
handler: (req: Request, res: Response, endpointRequest: HttpRequest, pluginData: T) => void) {
const isUpgrade = req.headers.connection?.toLowerCase() === 'upgrade';
const end = (code: number, message: string) => {
if (isUpgrade) {
const socket = res.socket;
socket.write(`HTTP/1.1 ${code} ${message}\r\n` +
'\r\n');
socket.destroy();
}
else {
res.status(code);
res.send(message);
}
};
if (!isPublicEndpoint && !res.locals.username) {
end(401, 'Not Authorized');
return;
}
const { owner, pkg } = req.params;
let endpoint = pkg;
if (owner)
endpoint = `@${owner}/${endpoint}`;
if (isUpgrade && req.headers.upgrade?.toLowerCase() !== 'websocket') {
end(404, 'Not Found');
return;
}
const pluginData = await this.getEndpointPluginData(endpoint, isUpgrade, isEngineIOEndpoint);
if (!pluginData) {
end(404, 'Not Found');
return;
}
let rootPath = `/endpoint/${endpoint}`;
if (isPublicEndpoint)
rootPath += '/public'
const body = req.body && typeof req.body !== 'string' ? JSON.stringify(req.body) : req.body;
const httpRequest: HttpRequest = {
body,
headers: req.headers,
method: req.method,
rootPath,
url: req.url,
isPublicEndpoint,
username: res.locals.username,
};
if (isEngineIOEndpoint && !isUpgrade && isPublicEndpoint) {
res.header("Access-Control-Allow-Origin", '*');
}
if (!isEngineIOEndpoint && isUpgrade) {
this.wss.handleUpgrade(req, req.socket, (req as any).upgradeHead, async (ws) => {
try {
await this.handleWebSocket(endpoint, httpRequest, ws, pluginData);
}
catch (e) {
console.error('websocket plugin error', e);
ws.close();
}
});
}
else {
try {
handler(req, res, httpRequest, pluginData);
}
catch (e) {
res.status(500);
res.send(e.toString());
console.error(e);
}
}
}
}