This commit is contained in:
Koushik Dutta
2023-03-19 18:26:42 -07:00
6 changed files with 127 additions and 14 deletions

View File

@@ -32,6 +32,8 @@ Do not enable prebuffer on Ring cameras and doorbells.
- Water Sensor
- Mailbox Sensor
- Smart Locks
- Ring Smart Lights (Flood/Path/Step/Spot Lights, Bulbs, Transformer)
- Lights, Switches & Outlets
## Problems and Solutions

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/ring",
"version": "0.0.103",
"version": "0.0.104",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/ring",
"version": "0.0.103",
"version": "0.0.104",
"dependencies": {
"@koush/ring-client-api": "file:../../external/ring-client-api",
"@scrypted/common": "file:../../common",

View File

@@ -44,5 +44,5 @@
"got": "11.8.6",
"socket.io-client": "^2.5.0"
},
"version": "0.0.103"
"version": "0.0.104"
}

View File

@@ -1,7 +1,7 @@
import sdk, { Battery, Device, DeviceProvider, EntrySensor, FloodSensor, Lock, LockState, MotionSensor, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, SecuritySystem, SecuritySystemMode, TamperSensor } from '@scrypted/sdk';
import sdk, { Battery, Brightness, Device, DeviceProvider, EntrySensor, FloodSensor, Lock, LockState, MotionSensor, OnOff, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, SecuritySystem, SecuritySystemMode, TamperSensor } from '@scrypted/sdk';
import { RingCameraDevice } from './camera';
import RingPlugin from './main';
import { Location, LocationMode, RingCamera, RingDevice, RingDeviceData, RingDeviceType } from './ring-client-api';
import { Location, LocationMode, RingCamera, RingDevice, RingDeviceCategory, RingDeviceData, RingDeviceType } from './ring-client-api';
const { deviceManager } = sdk;
@@ -11,6 +11,8 @@ class RingLock extends ScryptedDeviceBase implements Battery, Lock {
constructor(nativeId: string, device: RingDevice) {
super(nativeId);
this.device = device;
this.updateState(device.data);
device.onData.subscribe(async (data: RingDeviceData) => {
this.updateState(data);
});
@@ -42,7 +44,7 @@ class RingLock extends ScryptedDeviceBase implements Battery, Lock {
}
}
class RingSensor extends ScryptedDeviceBase implements TamperSensor, Battery, EntrySensor, MotionSensor, FloodSensor {
class RingLight extends ScryptedDeviceBase implements Battery, TamperSensor, MotionSensor, OnOff, Brightness {
device: RingDevice;
data: RingDeviceData;
@@ -58,16 +60,93 @@ class RingSensor extends ScryptedDeviceBase implements TamperSensor, Battery, En
});
}
private isBeamDevice() {
return [RingDeviceType.BeamsMultiLevelSwitch, RingDeviceType.BeamsSwitch, RingDeviceType.BeamsTransformerSwitch].includes(this.device.deviceType);
}
updateState(data: RingDeviceData) {
this.tampered = data.tamperStatus === 'tamper';
this.batteryLevel = data.batteryLevel;
this.tampered = data.tamperStatus === 'tamper';
this.motionDetected = data.motionStatus === 'faulted';
this.on = data.on;
this.brightness = data.level && !isNaN(data.level) ? 100 * data.level : 0;
}
turnOff(): Promise<void> {
if (this.isBeamDevice()) {
this.device.sendCommand('light-mode.set', { lightMode: 'default' });
return;
} else {
return this.device.setInfo({ device: { v1: { on: false } } });
}
}
turnOn(): Promise<void> {
if (this.isBeamDevice()) {
this.device.sendCommand('light-mode.set', { lightMode: 'on' });
return;
} else {
return this.device.setInfo({ device: { v1: { on: true } } });
}
}
setBrightness(brightness: number): Promise<void> {
return this.device.setInfo({
device: { v1: { level: brightness / 100 } },
});
}
}
class RingSwitch extends ScryptedDeviceBase implements OnOff {
device: RingDevice;
data: RingDeviceData;
constructor(nativeId: string, device: RingDevice) {
super(nativeId);
this.device = device;
this.updateState(device.data);
device.onData.subscribe(async (data: RingDeviceData) => {
this.updateState(data);
});
}
updateState(data: RingDeviceData) {
this.on = data.on;
}
turnOff(): Promise<void> {
return this.device.setInfo({ device: { v1: { on: false } } });
}
turnOn(): Promise<void> {
return this.device.setInfo({ device: { v1: { on: true } } });
}
}
class RingSensor extends ScryptedDeviceBase implements TamperSensor, Battery, EntrySensor, MotionSensor, FloodSensor {
device: RingDevice;
constructor(nativeId: string, device: RingDevice) {
super(nativeId);
this.device = device;
this.updateState(device.data);
device.onData.subscribe(async (data: RingDeviceData) => {
this.updateState(data);
});
}
updateState(data: RingDeviceData) {
this.batteryLevel = data.batteryLevel;
this.tampered = data.tamperStatus === 'tamper';
this.entryOpen = data.faulted;
this.motionDetected = this.device.deviceType === RingDeviceType.BeamsMotionSensor ? data.motionStatus === 'faulted' : data.faulted;
this.flooded = data.flood?.faulted || data.faulted;
}
isBypassable() {
return (this.device.deviceType === RingDeviceType.ContactSensor || this.device.deviceType === RingDeviceType.RetrofitZone) && this.data.faulted;
return (this.device.deviceType === RingDeviceType.ContactSensor || this.device.deviceType === RingDeviceType.RetrofitZone) && this.device.data.faulted;
}
}
@@ -168,25 +247,51 @@ export class RingLocationDevice extends ScryptedDeviceBase implements DeviceProv
case RingDeviceType.TiltSensor:
case RingDeviceType.GlassbreakSensor:
nativeId = locationDevice.id.toString() + '-sensor';
type = ScryptedDeviceType.Sensor
type = ScryptedDeviceType.Sensor;
interfaces.push(ScryptedInterface.TamperSensor, ScryptedInterface.EntrySensor);
break;
case RingDeviceType.MotionSensor:
case RingDeviceType.BeamsMotionSensor:
nativeId = locationDevice.id.toString() + '-sensor';
type = ScryptedDeviceType.Sensor
type = ScryptedDeviceType.Sensor;
interfaces.push(ScryptedInterface.TamperSensor, ScryptedInterface.MotionSensor);
break;
case RingDeviceType.FloodFreezeSensor:
case RingDeviceType.WaterSensor:
nativeId = locationDevice.id.toString() + '-sensor';
type = ScryptedDeviceType.Sensor
type = ScryptedDeviceType.Sensor;
interfaces.push(ScryptedInterface.TamperSensor, ScryptedInterface.FloodSensor);
break;
case RingDeviceType.BeamsMultiLevelSwitch:
case RingDeviceType.BeamsSwitch:
case RingDeviceType.BeamsTransformerSwitch:
case RingDeviceType.MultiLevelBulb:
nativeId = locationDevice.id.toString() + '-light';
type = ScryptedDeviceType.Light;
interfaces.push(ScryptedInterface.OnOff);
if (data.level !== undefined)
interfaces.push(ScryptedInterface.Brightness)
if (data.motionStatus !== undefined && !!data.motionSensorEnabled)
interfaces.push(ScryptedInterface.TamperSensor, ScryptedInterface.MotionSensor);
break;
case RingDeviceType.MultiLevelSwitch:
if (data.categoryId === RingDeviceCategory.Lights) {
nativeId = locationDevice.id.toString() + '-light';
type = ScryptedDeviceType.Light;
interfaces.push(ScryptedInterface.OnOff);
if (data.level !== undefined)
interfaces.push(ScryptedInterface.Brightness)
break;
}
case RingDeviceType.Switch:
nativeId = locationDevice.id.toString() + '-switch';
type = data.categoryId === RingDeviceCategory.Outlets ? ScryptedDeviceType.Outlet : ScryptedDeviceType.Switch;
interfaces.push(ScryptedInterface.OnOff);
break;
default:
if (/^lock($|\.)/.test(data.deviceType)) {
nativeId = locationDevice.id.toString() + '-lock';
type = ScryptedDeviceType.Lock
type = ScryptedDeviceType.Lock;
interfaces.push(ScryptedInterface.Lock);
break;
} else {
@@ -228,6 +333,12 @@ export class RingLocationDevice extends ScryptedDeviceBase implements DeviceProv
} else if (nativeId.endsWith('-lock')) {
const device = new RingLock(nativeId, this.locationDevices.get(nativeId) as RingDevice);
this.devices.set(nativeId, device);
} else if (nativeId.endsWith('-light')) {
const device = new RingLight(nativeId, this.locationDevices.get(nativeId) as RingDevice);
this.devices.set(nativeId, device);
} else if (nativeId.endsWith('-switch')) {
const device = new RingSwitch(nativeId, this.locationDevices.get(nativeId) as RingDevice);
this.devices.set(nativeId, device);
} else {
const device = new RingCameraDevice(this.plugin.api, nativeId, this.locationDevices.get(nativeId) as RingCamera);
this.devices.set(nativeId, device);

View File

@@ -9,6 +9,6 @@ export { BasicPeerConnection } from '@koush/ring-client-api/packages/ring-client
export { SimpleWebRtcSession } from '@koush/ring-client-api/packages/ring-client-api/streaming/simple-webrtc-session';
export { StreamingSession } from '@koush/ring-client-api/packages/ring-client-api/streaming/streaming-session';
export { generateUuid } from '@koush/ring-client-api/packages/ring-client-api/util';
export { RingDeviceType, RingDeviceData } from '@koush/ring-client-api/packages/ring-client-api/ring-types';
export { RingDeviceType, RingDeviceData, RingDeviceCategory } from '@koush/ring-client-api/packages/ring-client-api/ring-types';
export { RingDevice } from '@koush/ring-client-api/packages/ring-client-api/ring-device';
export * as rxjs from '@koush/ring-client-api/node_modules/rxjs';

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/server",
"version": "0.7.20",
"version": "0.7.21",
"description": "",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.10",