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

This commit is contained in:
Koushik Dutta
2022-01-27 20:48:57 -08:00
30 changed files with 174 additions and 83 deletions

View File

@@ -37,12 +37,14 @@ export abstract class SettingsMixinDeviceBase<T> extends MixinDeviceBase<T & Set
}
catch (e) {
const name = this.name;
const description = `${name} Extension settings failed to load.`;
this.console.error(description, e)
allSettings.push({
key: Math.random().toString(),
title: name,
value: 'Settings Error',
group: 'Errors',
description: `${name} Extension settings failed to load.`,
description,
readonly: true,
});
}
@@ -57,12 +59,14 @@ export abstract class SettingsMixinDeviceBase<T> extends MixinDeviceBase<T & Set
}
catch (e) {
const name = deviceManager.getDeviceState(this.mixinProviderNativeId).name;
const description = `${name} Extension settings failed to load.`;
this.console.error(description, e)
allSettings.push({
key: Math.random().toString(),
title: name,
value: 'Settings Error',
group: 'Errors',
description: `${name} Extension settings failed to load.`,
description,
readonly: true,
});
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.84",
"version": "0.0.85",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/hikvision",
"version": "0.0.84",
"version": "0.0.85",
"license": "Apache",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.84",
"version": "0.0.85",
"description": "HikVision Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -52,21 +52,22 @@ export class HikVisionCameraAPI {
resolve(deviceModel);
} catch (e) {
this.console.error('error checking NVR model', e);
resolve("unknown");
resolve(undefined);
}
});
}
return await this.deviceModel;
}
async checkIsOldModel(): Promise<boolean> {
async checkIsOldModel() {
// The old Hikvision DS-7608NI-E2 doesn't support channel capability checks, and the requests cause errors
const model = await this.checkDeviceModel();
if (!model)
return;
return !!model?.match(/DS-7608NI-E2/);
}
async checkStreamSetup(channel: string): Promise<HikVisionCameraStreamSetup> {
const isOld = await this.checkIsOldModel();
async checkStreamSetup(channel: string, isOld: boolean): Promise<HikVisionCameraStreamSetup> {
if (isOld) {
this.console.error('NVR is old version. Defaulting camera capabilities to H.264/AAC');
return {

View File

@@ -2,14 +2,33 @@ import sdk, { MediaObject, Camera, ScryptedInterface } from "@scrypted/sdk";
import { EventEmitter } from "stream";
import { HikVisionCameraAPI } from "./hikvision-camera-api";
import { Destroyable, UrlMediaStreamOptions, RtspProvider, RtspSmartCamera } from "../../rtsp/src/rtsp";
import { sleep } from "../../../common/src/sleep";
import { HikVisionCameraEvent } from "./hikvision-camera-api";
const { mediaManager } = sdk;
class HikVisionCamera extends RtspSmartCamera implements Camera {
hasCheckedCodec = false;
channelIds: Promise<string[]>;
client: HikVisionCameraAPI;
// bad hack, but whatever.
codecCheck = (async () => {
while (true) {
try {
const streamSetup = await this.client.checkStreamSetup(this.getRtspChannel(), await this.isOld());
if (streamSetup.videoCodecType !== 'H.264') {
this.log.a(`This camera is configured for ${streamSetup.videoCodecType} on the main channel. Configuring it it for H.264 is recommended for optimal performance.`);
}
if (!this.isAudioDisabled() && streamSetup.audioCodecType && streamSetup.audioCodecType !== 'AAC') {
this.log.a(`This camera is configured for ${streamSetup.audioCodecType} on the main channel. Configuring it for AAC is recommended for optimal performance.`);
}
break;
}
catch (e) {
await sleep(60000);
}
}
})();
listenEvents() {
let motionTimeout: NodeJS.Timeout;
const ret = new EventEmitter() as (EventEmitter & Destroyable);
@@ -84,19 +103,6 @@ class HikVisionCamera extends RtspSmartCamera implements Camera {
getClient() {
if (!this.client)
this.client = this.createClient();
(async () => {
if (this.hasCheckedCodec)
return;
const streamSetup = await this.client.checkStreamSetup(this.getRtspChannel());
this.hasCheckedCodec = true;
if (streamSetup.videoCodecType !== 'H.264') {
this.log.a(`This camera is configured for ${streamSetup.videoCodecType} on the main channel. Configuring it it for H.264 is recommended for optimal performance.`);
}
if (!this.isAudioDisabled() && streamSetup.audioCodecType && streamSetup.audioCodecType !== 'AAC') {
this.log.a(`This camera is configured for ${streamSetup.audioCodecType} on the main channel. Configuring it for AAC is recommended for optimal performance.`);
}
})();
return this.client;
}
@@ -142,11 +148,25 @@ class HikVisionCamera extends RtspSmartCamera implements Camera {
return this.storage.getItem('rtspUrlParams') || '?transportmode=unicast';
}
async isOld() {
const client = this.getClient();
let isOld: boolean;
if (this.storage.getItem('isOld')) {
isOld = this.storage.getItem('isOld') === 'true';
}
else {
isOld = await client.checkIsOldModel();
this.storage.setItem('isOld', isOld?.toString());
}
return isOld;
}
async getConstructedVideoStreamOptions(): Promise<UrlMediaStreamOptions[]> {
if (!this.channelIds) {
const client = this.getClient();
this.channelIds = new Promise(async (resolve, reject) => {
const isOld = await client.checkIsOldModel();
const isOld = await this.isOld();
if (isOld) {
this.console.error('Old NVR. Defaulting to two camera configuration');
const camNumber = this.getCameraNumber() || '1';

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/homekit",
"version": "0.0.173",
"version": "0.0.176",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/homekit",
"version": "0.0.173",
"version": "0.0.176",
"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.173"
"version": "0.0.176"
}

View File

@@ -198,6 +198,7 @@ addSupportedType({
return;
const reconfigured: MediaStreamOptions = Object.assign({
id: selectedStream?.id,
video: {
},
}, selectedStream || {});

View File

@@ -1,5 +1,5 @@
import { Entry, ScryptedDevice, ScryptedDeviceType, ScryptedInterface } from '@scrypted/sdk'
import { Entry, EntrySensor, ScryptedDevice, ScryptedDeviceType, ScryptedInterface } from '@scrypted/sdk'
import { addSupportedType, bindCharacteristic, DummyDevice } from '../common'
import { Characteristic, CharacteristicEventTypes, CharacteristicSetCallback, CharacteristicValue, NodeCallback, Service } from '../hap';
import { makeAccessory } from './common';
@@ -9,7 +9,7 @@ addSupportedType({
probe(device: DummyDevice): boolean {
return device.interfaces.includes(ScryptedInterface.Entry) && device.interfaces.includes(ScryptedInterface.EntrySensor);
},
getAccessory: async (device: ScryptedDevice & Entry) => {
getAccessory: async (device: ScryptedDevice & Entry & EntrySensor) => {
const accessory = makeAccessory(device);
const service = accessory.addService(Service.GarageDoorOpener, device.name);

View File

@@ -1,5 +1,5 @@
import { VideoCamera, MediaPlayer, MediaPlayerState, ScryptedDevice, ScryptedDeviceType, ScryptedInterface } from '@scrypted/sdk'
import { VideoCamera, MediaPlayer, MediaPlayerState, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, StartStop } from '@scrypted/sdk'
import { addSupportedType, bindCharacteristic, DummyDevice } from '../common'
import { Categories, Characteristic, CharacteristicEventTypes, CharacteristicSetCallback, CharacteristicValue, NodeCallback, Service } from '../hap';
import { makeAccessory } from './common';
@@ -12,7 +12,7 @@ addSupportedType({
probe(device: DummyDevice) {
return device.interfaces.includes(ScryptedInterface.MediaPlayer);
},
getAccessory: async (device: ScryptedDevice & MediaPlayer) => {
getAccessory: async (device: ScryptedDevice & MediaPlayer & StartStop) => {
const accessory = makeAccessory(device);
accessory.category = Categories.TELEVISION;
const service = accessory.addService(Service.Television, "Television", "Television");

View File

@@ -1,5 +1,5 @@
import { MotionSensor, BinarySensor, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, Thermometer } from '@scrypted/sdk'
import { MotionSensor, BinarySensor, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, Thermometer, HumiditySensor, AudioSensor, AmbientLightSensor } from '@scrypted/sdk'
import { addSupportedType, bindCharacteristic, DummyDevice } from '../common'
import { Characteristic, Service } from '../hap';
import { makeAccessory } from './common';
@@ -9,21 +9,30 @@ addSupportedType({
probe(device: DummyDevice) {
return device.interfaces.includes(ScryptedInterface.Thermometer) || device.interfaces.includes(ScryptedInterface.BinarySensor) || device.interfaces.includes(ScryptedInterface.MotionSensor);
},
getAccessory: async (device: ScryptedDevice & BinarySensor & MotionSensor & Thermometer) => {
getAccessory: async (device: ScryptedDevice & AmbientLightSensor & AudioSensor & BinarySensor & MotionSensor & Thermometer & HumiditySensor) => {
const accessory = makeAccessory(device);
if (device.interfaces.includes(ScryptedInterface.BinarySensor)) {
const contactSensorService = accessory.addService(Service.ContactSensor, device.name);
contactSensorService.getCharacteristic(Characteristic.ContactSensorState)
bindCharacteristic(device, ScryptedInterface.BinarySensor, contactSensorService, Characteristic.ContactSensorState,
const service = accessory.addService(Service.ContactSensor, device.name);
bindCharacteristic(device, ScryptedInterface.BinarySensor, service, Characteristic.ContactSensorState,
() => !!device.binaryState);
}
if (device.interfaces.includes(ScryptedInterface.MotionSensor)) {
const motionSensorService = accessory.addService(Service.MotionSensor, device.name);
if (device.interfaces.includes(ScryptedInterface.AmbientLightSensor)) {
const service = accessory.addService(Service.LightSensor, device.name);
bindCharacteristic(device, ScryptedInterface.AmbientLightSensor, service, Characteristic.CurrentAmbientLightLevel,
() => device.ambientLight || 0);
}
bindCharacteristic(device, ScryptedInterface.MotionSensor, motionSensorService, Characteristic.MotionDetected,
if (device.interfaces.includes(ScryptedInterface.AudioSensor)) {
const service = accessory.addService(Service.ContactSensor, device.name + ' Alarm Sound', 'AudioSensor');
bindCharacteristic(device, ScryptedInterface.AudioSensor, service, Characteristic.ContactSensorState,
() => !!device.audioDetected);
}
if (device.interfaces.includes(ScryptedInterface.MotionSensor)) {
const service = accessory.addService(Service.MotionSensor, device.name);
bindCharacteristic(device, ScryptedInterface.MotionSensor, service, Characteristic.MotionDetected,
() => !!device.motionDetected, true);
}
@@ -31,7 +40,12 @@ addSupportedType({
const service = accessory.addService(Service.TemperatureSensor, device.name);
bindCharacteristic(device, ScryptedInterface.Thermometer, service, Characteristic.CurrentTemperature,
() => device.temperature || 0);
}
if (device.interfaces.includes(ScryptedInterface.HumiditySensor)) {
const service = accessory.addService(Service.HumiditySensor, device.name);
bindCharacteristic(device, ScryptedInterface.HumiditySensor, service, Characteristic.CurrentRelativeHumidity,
() => device.humidity || 0);
}
// todo: more sensors.

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/mqtt",
"version": "0.0.36",
"version": "0.0.37",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/mqtt",
"version": "0.0.36",
"version": "0.0.37",
"dependencies": {
"@types/node": "^16.6.1",
"aedes": "^0.46.1",

View File

@@ -38,5 +38,5 @@
"@scrypted/sdk": "file:../../sdk",
"@types/nunjucks": "^3.2.0"
},
"version": "0.0.36"
"version": "0.0.37"
}

View File

@@ -1,6 +1,6 @@
import { ScryptedDeviceType, ScryptedInterface } from "@scrypted/sdk";
export function canMixin(type: ScryptedDeviceType, interfaces: string[]): boolean {
export function isPublishable(type: ScryptedDeviceType, interfaces: string[]): boolean {
const set = new Set(interfaces);
set.delete(ScryptedInterface.ObjectDetection);
set.delete(ScryptedInterface.DeviceDiscovery);
@@ -13,5 +13,6 @@ export function canMixin(type: ScryptedDeviceType, interfaces: string[]): boolea
set.delete(ScryptedInterface.Settings);
set.delete(ScryptedInterface.Readme);
set.delete(ScryptedInterface.BufferConverter);
set.delete(ScryptedInterface.ScryptedPlugin);
return !!set.size;
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/unifi-protect",
"version": "0.0.84",
"version": "0.0.88",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/unifi-protect",
"version": "0.0.84",
"version": "0.0.88",
"license": "Apache",
"dependencies": {
"@koush/unifi-protect": "file:../../external/unifi-protect",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/unifi-protect",
"version": "0.0.84",
"version": "0.0.88",
"description": "Unifi Protect Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -10,11 +10,15 @@ 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.nativeId}/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.nativeId}/open`, {
method: 'POST',
});
}
findLock() {

View File

@@ -30,9 +30,6 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
}
handleUpdatePacket(packet: any): void {
if (packet.action?.modelKey !== "camera") {
return;
}
if (packet.action.action !== "update") {
return;
}
@@ -42,6 +39,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
const device = this.api.cameras?.find(c => c.id === packet.action.id)
|| this.api.lights?.find(c => c.id === packet.action.id)
|| this.api.doorlocks?.find(c => c.id === packet.action.id)
|| this.api.sensors?.find(c => c.id === packet.action.id);
if (!device) {
@@ -69,6 +67,8 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
listener = (event: Buffer) => {
const updatePacket = ProtectApiUpdates.decodeUpdatePacket(this.console, event);
this.console.log('update', updatePacket);
this.handleUpdatePacket(updatePacket);
if (!updatePacket) {
@@ -270,7 +270,7 @@ export class UnifiProtect extends ScryptedDeviceBase implements Settings, Device
}
if (!this.api) {
this.api = new ProtectApi(ip, username, password, this.console);
this.api = new ProtectApi(ip, username, password);
}
try {

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/webhook",
"version": "0.0.16",
"version": "0.0.17",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/webhook",
"version": "0.0.16",
"version": "0.0.17",
"dependencies": {
"@types/node": "^16.6.1"
},

View File

@@ -33,5 +33,5 @@
"devDependencies": {
"@scrypted/sdk": "file:../../sdk"
},
"version": "0.0.16"
"version": "0.0.17"
}

View File

@@ -6,6 +6,8 @@ import { randomBytes } from 'crypto';
const allInterfaceMethods: string[] = [].concat(...Object.values(ScryptedInterfaceDescriptors).map((type: any) => type.methods));
const allInterfaceProperties: string[] = [].concat(...Object.values(ScryptedInterfaceDescriptors).map((type: any) => type.properties));
import { isPublishable} from '../../mqtt/src/publishable-types';
const { systemManager, endpointManager, mediaManager } = sdk;
const mediaObjectMethods = [
@@ -187,19 +189,7 @@ class WebhookPlugin extends ScryptedDeviceBase implements Settings, MixinProvide
}
async canMixin(type: ScryptedDeviceType, interfaces: string[]): Promise<string[]> {
const set = new Set(interfaces);
set.delete(ScryptedInterface.ObjectDetection);
set.delete(ScryptedInterface.DeviceDiscovery);
set.delete(ScryptedInterface.DeviceCreator);
set.delete(ScryptedInterface.DeviceProvider);
set.delete(ScryptedInterface.MixinProvider);
set.delete(ScryptedInterface.PushHandler);
set.delete(ScryptedInterface.EngineIOHandler);
set.delete(ScryptedInterface.HttpRequestHandler);
set.delete(ScryptedInterface.Settings);
set.delete(ScryptedInterface.Readme);
set.delete(ScryptedInterface.BufferConverter);
if (!set.size)
if (!isPublishable(type, interfaces))
return;
return [
ScryptedInterface.Settings,

View File

@@ -633,6 +633,12 @@ export interface AudioSensor {
export interface MotionSensor {
motionDetected?: boolean;
}
export interface AmbientLightSensor {
/**
* The ambient light in lux.
*/
ambientLight: number;
}
export interface OccupancySensor {
occupied?: boolean;
}
@@ -1230,6 +1236,7 @@ export enum ScryptedInterface {
PowerSensor = "PowerSensor",
AudioSensor = "AudioSensor",
MotionSensor = "MotionSensor",
AmbientLightSensor = "AmbientLightSensor",
OccupancySensor = "OccupancySensor",
FloodSensor = "FloodSensor",
UltravioletSensor = "UltravioletSensor",

4
sdk/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/sdk",
"version": "0.0.148",
"version": "0.0.151",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/sdk",
"version": "0.0.148",
"version": "0.0.151",
"license": "ISC",
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.14.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/sdk",
"version": "0.0.148",
"version": "0.0.151",
"description": "",
"main": "index.js",
"scripts": {

View File

@@ -59,6 +59,7 @@ class ScryptedDeviceType(Enum):
Valve = "Valve"
class ScryptedInterface(Enum):
AmbientLightSensor = "AmbientLightSensor"
AudioSensor = "AudioSensor"
Authenticator = "Authenticator"
Battery = "Battery"
@@ -417,6 +418,10 @@ class Setting(TypedDict):
value: SettingValue
pass
class AmbientLightSensor:
ambientLight: float
pass
class AudioSensor:
audioDetected: bool
pass
@@ -935,6 +940,7 @@ class ScryptedInterfaceProperty(Enum):
powerDetected = "powerDetected"
audioDetected = "audioDetected"
motionDetected = "motionDetected"
ambientLight = "ambientLight"
occupied = "occupied"
flooded = "flooded"
ultraviolet = "ultraviolet"
@@ -1236,6 +1242,13 @@ class DeviceState:
def motionDetected(self, value: bool):
self.setScryptedProperty("motionDetected", value)
@property
def ambientLight(self) -> float:
self.getScryptedProperty("ambientLight")
@ambientLight.setter
def ambientLight(self, value: float):
self.setScryptedProperty("ambientLight", value)
@property
def occupied(self) -> bool:
self.getScryptedProperty("occupied")

10
sdk/types.d.ts vendored
View File

@@ -41,6 +41,7 @@ export interface DeviceState {
powerDetected?: boolean;
audioDetected?: boolean;
motionDetected?: boolean;
ambientLight?: number;
occupied?: boolean;
flooded?: boolean;
ultraviolet?: number;
@@ -91,6 +92,7 @@ export declare class DeviceBase implements DeviceState {
powerDetected?: boolean;
audioDetected?: boolean;
motionDetected?: boolean;
ambientLight?: number;
occupied?: boolean;
flooded?: boolean;
ultraviolet?: number;
@@ -141,6 +143,7 @@ export declare enum ScryptedInterfaceProperty {
powerDetected = "powerDetected",
audioDetected = "audioDetected",
motionDetected = "motionDetected",
ambientLight = "ambientLight",
occupied = "occupied",
flooded = "flooded",
ultraviolet = "ultraviolet",
@@ -728,6 +731,12 @@ export interface AudioSensor {
export interface MotionSensor {
motionDetected?: boolean;
}
export interface AmbientLightSensor {
/**
* The ambient light in lux.
*/
ambientLight: number;
}
export interface OccupancySensor {
occupied?: boolean;
}
@@ -1271,6 +1280,7 @@ export declare enum ScryptedInterface {
PowerSensor = "PowerSensor",
AudioSensor = "AudioSensor",
MotionSensor = "MotionSensor",
AmbientLightSensor = "AmbientLightSensor",
OccupancySensor = "OccupancySensor",
FloodSensor = "FloodSensor",
UltravioletSensor = "UltravioletSensor",

View File

@@ -47,6 +47,7 @@ var ScryptedInterfaceProperty;
ScryptedInterfaceProperty["powerDetected"] = "powerDetected";
ScryptedInterfaceProperty["audioDetected"] = "audioDetected";
ScryptedInterfaceProperty["motionDetected"] = "motionDetected";
ScryptedInterfaceProperty["ambientLight"] = "ambientLight";
ScryptedInterfaceProperty["occupied"] = "occupied";
ScryptedInterfaceProperty["flooded"] = "flooded";
ScryptedInterfaceProperty["ultraviolet"] = "ultraviolet";
@@ -404,6 +405,13 @@ exports.ScryptedInterfaceDescriptors = {
'motionDetected'
]
},
AmbientLightSensor: {
name: 'AmbientLightSensor',
methods: [],
properties: [
'ambientLight'
]
},
OccupancySensor: {
name: 'OccupancySensor',
methods: [],
@@ -650,6 +658,7 @@ var ScryptedInterface;
ScryptedInterface["PowerSensor"] = "PowerSensor";
ScryptedInterface["AudioSensor"] = "AudioSensor";
ScryptedInterface["MotionSensor"] = "MotionSensor";
ScryptedInterface["AmbientLightSensor"] = "AmbientLightSensor";
ScryptedInterface["OccupancySensor"] = "OccupancySensor";
ScryptedInterface["FloodSensor"] = "FloodSensor";
ScryptedInterface["UltravioletSensor"] = "UltravioletSensor";

View File

@@ -42,6 +42,7 @@ export interface DeviceState {
powerDetected?: boolean
audioDetected?: boolean
motionDetected?: boolean
ambientLight?: number
occupied?: boolean
flooded?: boolean
ultraviolet?: number
@@ -93,6 +94,7 @@ export class DeviceBase implements DeviceState {
powerDetected?: boolean
audioDetected?: boolean
motionDetected?: boolean
ambientLight?: number
occupied?: boolean
flooded?: boolean
ultraviolet?: number
@@ -145,6 +147,7 @@ export enum ScryptedInterfaceProperty {
powerDetected = "powerDetected",
audioDetected = "audioDetected",
motionDetected = "motionDetected",
ambientLight = "ambientLight",
occupied = "occupied",
flooded = "flooded",
ultraviolet = "ultraviolet",
@@ -505,6 +508,13 @@ export const ScryptedInterfaceDescriptors: { [scryptedInterface: string]: Scrypt
'motionDetected'
]
},
AmbientLightSensor: {
name: 'AmbientLightSensor',
methods: [],
properties: [
'ambientLight'
]
},
OccupancySensor: {
name: 'OccupancySensor',
methods: [],
@@ -1272,6 +1282,12 @@ export interface AudioSensor {
export interface MotionSensor {
motionDetected?: boolean;
}
export interface AmbientLightSensor {
/**
* The ambient light in lux.
*/
ambientLight: number;
}
export interface OccupancySensor {
occupied?: boolean;
}
@@ -1869,6 +1885,7 @@ export enum ScryptedInterface {
PowerSensor = "PowerSensor",
AudioSensor = "AudioSensor",
MotionSensor = "MotionSensor",
AmbientLightSensor = "AmbientLightSensor",
OccupancySensor = "OccupancySensor",
FloodSensor = "FloodSensor",
UltravioletSensor = "UltravioletSensor",

View File

@@ -1,17 +1,17 @@
{
"name": "@scrypted/server",
"version": "0.0.133",
"version": "0.0.134",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/server",
"version": "0.0.133",
"version": "0.0.134",
"license": "ISC",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.5",
"@scrypted/ffmpeg": "^1.0.9",
"@scrypted/sdk": "^0.0.148",
"@scrypted/sdk": "^0.0.151",
"adm-zip": "^0.5.3",
"axios": "^0.21.1",
"body-parser": "^1.19.0",
@@ -858,9 +858,9 @@
}
},
"node_modules/@scrypted/sdk": {
"version": "0.0.148",
"resolved": "https://registry.npmjs.org/@scrypted/sdk/-/sdk-0.0.148.tgz",
"integrity": "sha512-yXa7C99D4yLBIx3A4Ed8yAsxK3JeZKJ4X/rmjsWRYQHqGufy1Nl1Yza3eTubsyzPQHWQdrS58CmEcLDfa1+Z9Q==",
"version": "0.0.151",
"resolved": "https://registry.npmjs.org/@scrypted/sdk/-/sdk-0.0.151.tgz",
"integrity": "sha512-0xVuMvQcc76Df2T1BS7zpNpdFxwWJxX0XjMhBDxdArA+4kxr2oRXNUSY4g3sqIXG0Z5tLHJUSd3FZ1Mf1Uqm2g==",
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
@@ -5891,9 +5891,9 @@
}
},
"@scrypted/sdk": {
"version": "0.0.148",
"resolved": "https://registry.npmjs.org/@scrypted/sdk/-/sdk-0.0.148.tgz",
"integrity": "sha512-yXa7C99D4yLBIx3A4Ed8yAsxK3JeZKJ4X/rmjsWRYQHqGufy1Nl1Yza3eTubsyzPQHWQdrS58CmEcLDfa1+Z9Q==",
"version": "0.0.151",
"resolved": "https://registry.npmjs.org/@scrypted/sdk/-/sdk-0.0.151.tgz",
"integrity": "sha512-0xVuMvQcc76Df2T1BS7zpNpdFxwWJxX0XjMhBDxdArA+4kxr2oRXNUSY4g3sqIXG0Z5tLHJUSd3FZ1Mf1Uqm2g==",
"requires": {
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",

View File

@@ -1,11 +1,11 @@
{
"name": "@scrypted/server",
"version": "0.0.133",
"version": "0.0.134",
"description": "",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.5",
"@scrypted/ffmpeg": "^1.0.9",
"@scrypted/sdk": "^0.0.148",
"@scrypted/sdk": "^0.0.151",
"adm-zip": "^0.5.3",
"axios": "^0.21.1",
"body-parser": "^1.19.0",