mirror of
https://github.com/koush/scrypted.git
synced 2026-05-26 06:30:29 +01:00
unifi-protect: debounce motion sensors, attempt to stabilize nativeids
This commit is contained in:
2
plugins/unifi-protect/.vscode/launch.json
vendored
2
plugins/unifi-protect/.vscode/launch.json
vendored
@@ -17,7 +17,7 @@
|
||||
"sourceMaps": true,
|
||||
"localRoot": "${workspaceFolder}/out",
|
||||
"remoteRoot": "/plugin/",
|
||||
"type": "pwa-node"
|
||||
"type": "node"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { once } from "events";
|
||||
import { Readable } from "stream";
|
||||
import WS from 'ws';
|
||||
import { UnifiProtect } from "./main";
|
||||
import { MOTION_SENSOR_TIMEOUT, UnifiMotionDevice, debounceMotionDetected } from './motion';
|
||||
import { FeatureFlagsShim } from "./shim";
|
||||
import { ProtectCameraChannelConfig, ProtectCameraConfigInterface, ProtectCameraLcdMessagePayload } from "./unifi-protect";
|
||||
|
||||
@@ -39,11 +40,10 @@ export class UnifiPackageCamera extends ScryptedDeviceBase implements Camera, Vi
|
||||
}
|
||||
}
|
||||
|
||||
export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Intercom, Camera, VideoCamera, VideoCameraConfiguration, MotionSensor, Settings, ObjectDetector, DeviceProvider, OnOff, PanTiltZoom, Online {
|
||||
export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Intercom, Camera, VideoCamera, VideoCameraConfiguration, MotionSensor, Settings, ObjectDetector, DeviceProvider, OnOff, PanTiltZoom, Online, UnifiMotionDevice {
|
||||
motionTimeout: NodeJS.Timeout;
|
||||
detectionTimeout: NodeJS.Timeout;
|
||||
ringTimeout: NodeJS.Timeout;
|
||||
lastMotion: number;
|
||||
lastRing: number;
|
||||
lastSeen: number;
|
||||
intercomProcess?: ChildProcess;
|
||||
@@ -51,7 +51,6 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
|
||||
constructor(public protect: UnifiProtect, nativeId: string, protectCamera: Readonly<ProtectCameraConfigInterface>) {
|
||||
super(nativeId);
|
||||
this.lastMotion = protectCamera?.lastMotion;
|
||||
this.lastRing = protectCamera?.lastRing;
|
||||
this.lastSeen = protectCamera?.lastSeen;
|
||||
|
||||
@@ -226,14 +225,14 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
}
|
||||
|
||||
async getSettings(): Promise<Setting[]> {
|
||||
const vsos = await this.getVideoStreamOptions();
|
||||
// const vsos = await this.getVideoStreamOptions();
|
||||
return [
|
||||
{
|
||||
title: 'Sensor Timeout',
|
||||
key: 'sensorTimeout',
|
||||
value: this.storage.getItem('sensorTimeout') || defaultSensorTimeout,
|
||||
description: 'Time to wait in seconds before clearing the motion, doorbell button, or object detection state.',
|
||||
}
|
||||
// {
|
||||
// title: 'Sensor Timeout',
|
||||
// key: 'sensorTimeout',
|
||||
// value: this.storage.getItem('sensorTimeout') || defaultSensorTimeout,
|
||||
// description: 'Time to wait in seconds before clearing the motion, doorbell button, or object detection state.',
|
||||
// }
|
||||
];
|
||||
}
|
||||
|
||||
@@ -242,17 +241,6 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
|
||||
}
|
||||
|
||||
getSensorTimeout() {
|
||||
return (parseInt(this.storage.getItem('sensorTimeout')) || 10) * 1000;
|
||||
}
|
||||
|
||||
resetMotionTimeout() {
|
||||
clearTimeout(this.motionTimeout);
|
||||
this.motionTimeout = setTimeout(() => {
|
||||
this.setMotionDetected(false);
|
||||
}, this.getSensorTimeout());
|
||||
}
|
||||
|
||||
resetDetectionTimeout() {
|
||||
clearTimeout(this.detectionTimeout);
|
||||
this.detectionTimeout = setTimeout(() => {
|
||||
@@ -261,14 +249,14 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
detections: []
|
||||
}
|
||||
this.onDeviceEvent(ScryptedInterface.ObjectDetector, detect);
|
||||
}, this.getSensorTimeout());
|
||||
}, MOTION_SENSOR_TIMEOUT);
|
||||
}
|
||||
|
||||
resetRingTimeout() {
|
||||
clearTimeout(this.ringTimeout);
|
||||
this.ringTimeout = setTimeout(() => {
|
||||
this.binaryState = false;
|
||||
}, this.getSensorTimeout());
|
||||
}, MOTION_SENSOR_TIMEOUT);
|
||||
}
|
||||
|
||||
async getSnapshot(options?: PictureOptions, suffix?: string): Promise<Buffer> {
|
||||
@@ -287,7 +275,7 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
catch (e) {
|
||||
|
||||
}
|
||||
const url = `https://${this.protect.getSetting('ip')}/proxy/protect/api/cameras/${this.nativeId}/${suffix}?ts=${Date.now()}${size}`
|
||||
const url = `https://${this.protect.getSetting('ip')}/proxy/protect/api/cameras/${this.findCamera().id}/${suffix}?ts=${Date.now()}${size}`
|
||||
|
||||
const abort = new AbortController();
|
||||
const timeout = setTimeout(() => abort.abort('Unifi Protect Snapshot timed out after 10 seconds. Aborted.'), 10000);
|
||||
@@ -307,7 +295,8 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
return this.createMediaObject(buffer, 'image/jpeg');
|
||||
}
|
||||
findCamera() {
|
||||
return this.protect.api.cameras.find(camera => camera.id === this.nativeId);
|
||||
const id = this.protect.findId(this.nativeId);
|
||||
return this.protect.api.cameras.find(camera => camera.id === id);
|
||||
}
|
||||
async getVideoStream(options?: MediaStreamOptions): Promise<MediaObject> {
|
||||
const camera = this.findCamera();
|
||||
@@ -424,7 +413,8 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
return;
|
||||
this.on = !!camera.ledSettings?.isEnabled;
|
||||
this.online = !!camera.isConnected;
|
||||
this.setMotionDetected(!!camera.isMotionDetected);
|
||||
if (!!camera.isMotionDetected)
|
||||
debounceMotionDetected(this);
|
||||
|
||||
if (!!camera.featureFlags.canOpticalZoom) {
|
||||
this.ptzCapabilities = { pan: false, tilt: false, zoom: true };
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { ScryptedDeviceBase, MotionSensor, TemperatureUnit, OnOff, Brightness } from "@scrypted/sdk";
|
||||
import { Brightness, MotionSensor, OnOff, ScryptedDeviceBase, TemperatureUnit } from "@scrypted/sdk";
|
||||
import { UnifiProtect } from "./main";
|
||||
import { UnifiMotionDevice, debounceMotionDetected } from "./motion";
|
||||
import { ProtectLightConfig } from "./unifi-protect";
|
||||
|
||||
export class UnifiLight extends ScryptedDeviceBase implements OnOff, Brightness, MotionSensor {
|
||||
export class UnifiLight extends ScryptedDeviceBase implements OnOff, Brightness, MotionSensor, UnifiMotionDevice {
|
||||
motionTimeout: NodeJS.Timeout;
|
||||
|
||||
constructor(public protect: UnifiProtect, nativeId: string, protectLight: Readonly<ProtectLightConfig>) {
|
||||
super(nativeId);
|
||||
this.temperatureUnit = TemperatureUnit.C;
|
||||
@@ -26,7 +29,8 @@ export class UnifiLight extends ScryptedDeviceBase implements OnOff, Brightness,
|
||||
}
|
||||
|
||||
findLight() {
|
||||
return this.protect.api.lights.find(light => light.id === this.nativeId);
|
||||
const id = this.protect.findId(this.nativeId);
|
||||
return this.protect.api.lights.find(light => light.id === id);
|
||||
}
|
||||
|
||||
updateState(light?: Readonly<ProtectLightConfig>) {
|
||||
@@ -36,7 +40,8 @@ export class UnifiLight extends ScryptedDeviceBase implements OnOff, Brightness,
|
||||
this.on = !!light.isLightOn;
|
||||
// The Protect ledLevel settings goes from 1 - 6. HomeKit expects percentages, so we convert it like so.
|
||||
this.brightness = (light.lightDeviceSettings.ledLevel - 1) * 20;
|
||||
this.setMotionDetected(!!light.isPirMotionDetected);
|
||||
if (!!light.isPirMotionDetected)
|
||||
debounceMotionDetected(this);
|
||||
}
|
||||
|
||||
setMotionDetected(motionDetected: boolean) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ScryptedDeviceBase, Lock, LockState } from "@scrypted/sdk";
|
||||
import { Lock, LockState, ScryptedDeviceBase } from "@scrypted/sdk";
|
||||
import { UnifiProtect } from "./main";
|
||||
import { ProtectDoorLockConfig } from "./unifi-protect";
|
||||
|
||||
@@ -11,19 +11,20 @@ export class UnifiLock extends ScryptedDeviceBase implements Lock {
|
||||
}
|
||||
|
||||
async lock(): Promise<void> {
|
||||
await this.protect.loginFetch(this.protect.api.doorlocksUrl() + `/${this.nativeId}/close`, {
|
||||
await this.protect.loginFetch(this.protect.api.doorlocksUrl() + `/${this.findLock().id}/close`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
async unlock(): Promise<void> {
|
||||
await this.protect.loginFetch(this.protect.api.doorlocksUrl() + `/${this.nativeId}/open`, {
|
||||
await this.protect.loginFetch(this.protect.api.doorlocksUrl() + `/${this.findLock().id}/open`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
findLock() {
|
||||
return this.protect.api.doorlocks.find(doorlock => doorlock.id === this.nativeId);
|
||||
const id = this.protect.findId(this.nativeId);
|
||||
return this.protect.api.doorlocks.find(doorlock => doorlock.id === id);
|
||||
}
|
||||
|
||||
updateState(lock?: Readonly<ProtectDoorLockConfig>) {
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import sdk, { ScryptedDeviceBase, DeviceProvider, Settings, Setting, ScryptedDeviceType, Device, ScryptedInterface, ObjectsDetected, ObjectDetectionResult } from "@scrypted/sdk";
|
||||
import { ProtectApi, ProtectApiUpdates, ProtectNvrUpdatePayloadCameraUpdate, ProtectNvrUpdatePayloadEventAdd } from "./unifi-protect";
|
||||
import { createInstanceableProviderPlugin, enableInstanceableProviderMode, isInstanceableProviderModeEnabled } from '@scrypted/common/src/provider-plugin';
|
||||
import { defaultSensorTimeout, UnifiCamera } from "./camera";
|
||||
import { FeatureFlagsShim, LastSeenShim } from "./shim";
|
||||
import { UnifiSensor } from "./sensor";
|
||||
import { sleep } from "@scrypted/common/src/sleep";
|
||||
import sdk, { Device, DeviceProvider, ObjectDetectionResult, ObjectsDetected, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, Setting, Settings } from "@scrypted/sdk";
|
||||
import { StorageSettings } from "@scrypted/sdk/storage-settings";
|
||||
import axios from "axios";
|
||||
import { UnifiCamera } from "./camera";
|
||||
import { UnifiLight } from "./light";
|
||||
import { UnifiLock } from "./lock";
|
||||
import { sleep } from "@scrypted/common/src/sleep";
|
||||
import axios from "axios";
|
||||
import { StorageSettings } from "@scrypted/sdk/storage-settings";
|
||||
import { debounceMotionDetected } from "./motion";
|
||||
import { UnifiSensor } from "./sensor";
|
||||
import { FeatureFlagsShim, LastSeenShim } from "./shim";
|
||||
import { ProtectApi, ProtectApiUpdates, ProtectNvrUpdatePayloadCameraUpdate, ProtectNvrUpdatePayloadEventAdd } from "./unifi-protect";
|
||||
|
||||
const { deviceManager } = sdk;
|
||||
|
||||
@@ -64,10 +65,12 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
|
||||
Object.assign(device, packet.payload);
|
||||
|
||||
const ret = this.sensors.get(packet.action.id) ||
|
||||
this.locks.get(packet.action.id) ||
|
||||
this.cameras.get(packet.action.id) ||
|
||||
this.lights.get(packet.action.id);
|
||||
const nativeId = this.getNativeId(device, false);
|
||||
|
||||
const ret = this.sensors.get(nativeId) ||
|
||||
this.locks.get(nativeId) ||
|
||||
this.cameras.get(nativeId) ||
|
||||
this.lights.get(nativeId);
|
||||
|
||||
const keys = new Set(Object.keys(packet.payload));
|
||||
for (const k of filter) {
|
||||
@@ -78,13 +81,6 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
return ret;
|
||||
}
|
||||
|
||||
sanityCheckMotion(device: UnifiCamera | UnifiSensor | UnifiLight, payload: ProtectNvrUpdatePayloadCameraUpdate & LastSeenShim) {
|
||||
if (device.motionDetected && payload.lastSeen > payload.lastMotion + defaultSensorTimeout) {
|
||||
// something weird happened, lets set unset any motion state
|
||||
device.setMotionDetected(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async loginFetch(url: string, options?: { method?: string, signal?: AbortSignal, responseType?: axios.ResponseType }) {
|
||||
const api = this.api as any;
|
||||
if (!(await api.login()))
|
||||
@@ -132,13 +128,12 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
return;
|
||||
|
||||
const payload = updatePacket.payload as any as ProtectNvrUpdatePayloadCameraUpdate & LastSeenShim;
|
||||
this.sanityCheckMotion(unifiDevice as any, payload);
|
||||
|
||||
if (updatePacket.action.modelKey !== "camera")
|
||||
return;
|
||||
|
||||
const unifiCamera = unifiDevice as UnifiCamera;
|
||||
if (payload.lastRing && unifiCamera.binaryState && payload.lastSeen > payload.lastRing + unifiCamera.getSensorTimeout()) {
|
||||
if (payload.lastRing && unifiCamera.binaryState && payload.lastSeen > payload.lastRing + 25000) {
|
||||
// something weird happened, lets set unset any binary sensor state
|
||||
unifiCamera.binaryState = false;
|
||||
}
|
||||
@@ -207,11 +202,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
unifiCamera.resetRingTimeout();
|
||||
}
|
||||
else if (payload.type === 'motion') {
|
||||
unifiCamera.setMotionDetected(true);
|
||||
unifiCamera.lastMotion = payload.start;
|
||||
// i don't think this is necessary anymore?
|
||||
// the event stream will set and unset motion.
|
||||
unifiCamera.resetMotionTimeout();
|
||||
debounceMotionDetected(unifiCamera);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +331,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
const d: Device = {
|
||||
providerNativeId: this.nativeId,
|
||||
name: camera.name,
|
||||
nativeId: camera.id,
|
||||
nativeId: this.getNativeId(camera, true),
|
||||
info: {
|
||||
manufacturer: 'Ubiquiti',
|
||||
model: camera.type,
|
||||
@@ -387,7 +378,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
const d: Device = {
|
||||
providerNativeId: this.nativeId,
|
||||
name: sensor.name,
|
||||
nativeId: sensor.id,
|
||||
nativeId: this.getNativeId(sensor, true),
|
||||
info: {
|
||||
manufacturer: 'Ubiquiti',
|
||||
model: sensor.type,
|
||||
@@ -414,7 +405,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
const d: Device = {
|
||||
providerNativeId: this.nativeId,
|
||||
name: light.name,
|
||||
nativeId: light.id,
|
||||
nativeId: this.getNativeId(light, true),
|
||||
info: {
|
||||
manufacturer: 'Ubiquiti',
|
||||
model: light.type,
|
||||
@@ -438,7 +429,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
const d: Device = {
|
||||
providerNativeId: this.nativeId,
|
||||
name: lock.name,
|
||||
nativeId: lock.id,
|
||||
nativeId: this.getNativeId(lock, true),
|
||||
info: {
|
||||
manufacturer: 'Ubiquiti',
|
||||
model: lock.type,
|
||||
@@ -470,7 +461,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
continue;
|
||||
const nativeId = camera.id + '-packageCamera';
|
||||
const d: Device = {
|
||||
providerNativeId: camera.id,
|
||||
providerNativeId: this.getNativeId(camera, true),
|
||||
name: camera.name + ' Package Camera',
|
||||
nativeId,
|
||||
info: {
|
||||
@@ -489,7 +480,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
};
|
||||
|
||||
await deviceManager.onDevicesChanged({
|
||||
providerNativeId: camera.id,
|
||||
providerNativeId: this.getNativeId(camera, true),
|
||||
devices: [d],
|
||||
});
|
||||
}
|
||||
@@ -513,25 +504,27 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
return this.lights.get(nativeId);
|
||||
if (this.locks.has(nativeId))
|
||||
return this.locks.get(nativeId);
|
||||
const camera = this.api.cameras.find(camera => camera.id === nativeId);
|
||||
|
||||
const id = this.findId(nativeId);
|
||||
const camera = this.api.cameras.find(camera => camera.id === id);
|
||||
if (camera) {
|
||||
const ret = new UnifiCamera(this, nativeId, camera);
|
||||
this.cameras.set(nativeId, ret);
|
||||
return ret;
|
||||
}
|
||||
const sensor = this.api.sensors.find(sensor => sensor.id === nativeId);
|
||||
const sensor = this.api.sensors.find(sensor => sensor.id === id);
|
||||
if (sensor) {
|
||||
const ret = new UnifiSensor(this, nativeId, sensor);
|
||||
this.sensors.set(nativeId, ret);
|
||||
return ret;
|
||||
}
|
||||
const light = this.api.lights.find(light => light.id === nativeId);
|
||||
const light = this.api.lights.find(light => light.id === id);
|
||||
if (light) {
|
||||
const ret = new UnifiLight(this, nativeId, light);
|
||||
this.lights.set(nativeId, ret);
|
||||
return ret;
|
||||
}
|
||||
const lock = this.api.doorlocks?.find(lock => lock.id === nativeId);
|
||||
const lock = this.api.doorlocks?.find(lock => lock.id === id);
|
||||
if (lock) {
|
||||
const ret = new UnifiLock(this, nativeId, lock);
|
||||
this.locks.set(nativeId, ret);
|
||||
@@ -576,8 +569,57 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
|
||||
group: 'Advanced',
|
||||
type: 'boolean',
|
||||
},
|
||||
idMaps: {
|
||||
hide: true,
|
||||
json: true,
|
||||
defaultValue: {
|
||||
mac: {},
|
||||
anonymousDeviceId: {},
|
||||
id: {},
|
||||
nativeId: {},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
findId(nativeId: string) {
|
||||
// the native id should be mapped to an id...
|
||||
return this.storageSettings.values.idMaps.nativeId?.[nativeId] || nativeId;
|
||||
}
|
||||
|
||||
getNativeId(device: any, update: boolean) {
|
||||
const { id, mac, anonymousDeviceId } = device;
|
||||
const idMaps = this.storageSettings.values.idMaps;
|
||||
|
||||
// try to find an existing nativeId given the mac and anonymous device id
|
||||
const found = (mac && idMaps.mac[mac]) || (anonymousDeviceId && idMaps.anonymousDeviceId[anonymousDeviceId]);
|
||||
|
||||
// use the found id if one exists (device got provisioned a new id), otherwise use the id provided by the device.
|
||||
const nativeId = found || id;
|
||||
|
||||
if (!update)
|
||||
return nativeId;
|
||||
|
||||
// map the mac and anonymous device id to the native id.
|
||||
if (mac) {
|
||||
idMaps.mac ||= {};
|
||||
idMaps.mac[mac] = nativeId;
|
||||
}
|
||||
if (anonymousDeviceId) {
|
||||
idMaps.anonymousDeviceId ||= {};
|
||||
idMaps.anonymousDeviceId[anonymousDeviceId] = nativeId;
|
||||
}
|
||||
|
||||
// map the id and native id to each other.
|
||||
idMaps.id ||= {};
|
||||
idMaps.id[id] = nativeId;
|
||||
|
||||
idMaps.nativeId ||= {};
|
||||
idMaps.nativeId[nativeId] = id;
|
||||
|
||||
this.storageSettings.values.idMaps = idMaps;
|
||||
return nativeId;
|
||||
}
|
||||
|
||||
async getSettings(): Promise<Setting[]> {
|
||||
const ret = await this.storageSettings.getSettings();
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { ScryptedDeviceBase, MotionSensor, BinarySensor, AudioSensor, HumiditySensor, Thermometer, TemperatureUnit } from "@scrypted/sdk";
|
||||
import { ProtectSensorConfig } from "./unifi-protect";
|
||||
import { AudioSensor, BinarySensor, HumiditySensor, MotionSensor, ScryptedDeviceBase, TemperatureUnit, Thermometer } from "@scrypted/sdk";
|
||||
import { UnifiProtect } from "./main";
|
||||
import { UnifiMotionDevice, debounceMotionDetected } from "./motion";
|
||||
import { ProtectSensorConfig } from "./unifi-protect";
|
||||
|
||||
export class UnifiSensor extends ScryptedDeviceBase implements Thermometer, HumiditySensor, AudioSensor, BinarySensor, MotionSensor, UnifiMotionDevice {
|
||||
motionTimeout: NodeJS.Timeout;
|
||||
|
||||
export class UnifiSensor extends ScryptedDeviceBase implements Thermometer, HumiditySensor, AudioSensor, BinarySensor, MotionSensor {
|
||||
constructor(public protect: UnifiProtect, nativeId: string, protectSensor: Readonly<ProtectSensorConfig>) {
|
||||
super(nativeId);
|
||||
this.temperatureUnit = TemperatureUnit.C;
|
||||
@@ -11,7 +14,8 @@ export class UnifiSensor extends ScryptedDeviceBase implements Thermometer, Humi
|
||||
}
|
||||
|
||||
findSensor() {
|
||||
return this.protect.api.sensors.find(sensor => sensor.id === this.nativeId);
|
||||
const id = this.protect.findId(this.nativeId);
|
||||
return this.protect.api.sensors.find(sensor => sensor.id === id);
|
||||
}
|
||||
|
||||
async setTemperatureUnit(temperatureUnit: TemperatureUnit): Promise<void> {
|
||||
@@ -28,7 +32,8 @@ export class UnifiSensor extends ScryptedDeviceBase implements Thermometer, Humi
|
||||
this.binaryState = sensor.isOpened;
|
||||
this.audioDetected = !!sensor.alarmTriggeredAt;
|
||||
this.flooded = !!sensor.leakDetectedAt;
|
||||
this.setMotionDetected(!!sensor.isMotionDetected);
|
||||
if (!!sensor.isMotionDetected)
|
||||
debounceMotionDetected(this);
|
||||
}
|
||||
|
||||
setMotionDetected(motionDetected: boolean) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"module": "Node16",
|
||||
"target": "ES2021",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "Node16",
|
||||
|
||||
Reference in New Issue
Block a user