diff --git a/.gitmodules b/.gitmodules index 536238afb..58d8e06ae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "plugins/myq/src/myq"] path = plugins/myq/src/myq url = git@github.com:koush/myq.git +[submodule "plugins/neato/node-botvac"] + path = plugins/neato/node-botvac + url = git@github.com:koush/node-botvac diff --git a/plugins/homekit/src/main.ts b/plugins/homekit/src/main.ts index 1a24c363d..ce644130e 100644 --- a/plugins/homekit/src/main.ts +++ b/plugins/homekit/src/main.ts @@ -32,9 +32,6 @@ class HAPLocalStorage { (HAPStorage as any).INSTANCE.localStore = new HAPLocalStorage(); -const mac = (Object.entries(os.networkInterfaces()).filter(([iface, entry]) => iface.startsWith('en') || iface.startsWith('wlan')) as any) - .flat().map(([iface, entry]) => entry).find(i => i.family == 'IPv4').mac; - function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); @@ -51,23 +48,38 @@ const uuid = localStorage.getItem('uuid'); const includeToken = 4; + class HomeKit extends ScryptedDeviceBase implements MixinProvider, Settings { bridge = new Bridge('Scrypted', uuid); + constructor() { super(); this.start(); } + + getUsername() { + return this.storage.getItem("mac") || (Object.entries(os.networkInterfaces()).filter(([iface, entry]) => iface.startsWith('en') || iface.startsWith('wlan')) as any) + .flat().map(([iface, entry]) => entry).find(i => i.family == 'IPv4').mac; + } + async getSettings(): Promise { return [ { title: "Pairing Code", + key: "pairingCode", readonly: true, value: "123-45-678", + }, + { + title: "Username Override", + value: this.getUsername(), + key: "mac", } ] } async putSetting(key: string, value: string | number | boolean): Promise { + this.storage.setItem(key, value.toString()); } async start() { @@ -123,7 +135,7 @@ class HomeKit extends ScryptedDeviceBase implements MixinProvider, Settings { this.storage.setItem('defaultIncluded', JSON.stringify(defaultIncluded)); this.bridge.publish({ - username: mac, + username: this.getUsername(), pincode: '123-45-678', port: Math.round(Math.random() * 30000 + 10000), }, true); diff --git a/plugins/neato/node-botvac b/plugins/neato/node-botvac new file mode 160000 index 000000000..60cfdc125 --- /dev/null +++ b/plugins/neato/node-botvac @@ -0,0 +1 @@ +Subproject commit 60cfdc1251e299a089f68cb89bee7e483a1b11cc diff --git a/plugins/neato/package-lock.json b/plugins/neato/package-lock.json index a27a83651..6cf03fb08 100644 --- a/plugins/neato/package-lock.json +++ b/plugins/neato/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "axios": "^0.19.2", "crypto-js": "^3.1.9-1", - "node-botvac": "github:koush/node-botvac#9aee6fb4e6963a38a94d77d9c43b85e83e8c90a7" + "node-botvac": "file:./node-botvac" }, "devDependencies": { "@scrypted/sdk": "file:../../sdk", @@ -21,7 +21,7 @@ }, "../../sdk": { "name": "@scrypted/sdk", - "version": "0.0.65", + "version": "0.0.69", "dev": true, "license": "ISC", "dependencies": { @@ -194,38 +194,8 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/node-botvac": { - "resolved": "git+ssh://git@github.com/koush/node-botvac.git#9aee6fb4e6963a38a94d77d9c43b85e83e8c90a7", - "dependencies": { - "axios": "^0.18.1" - } - }, - "node_modules/node-botvac/node_modules/axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", - "dependencies": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, - "node_modules/node-botvac/node_modules/follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "dependencies": { - "debug": "=3.1.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/node-botvac/node_modules/is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", - "engines": { - "node": ">=4" - } + "resolved": "node-botvac", + "link": true }, "node_modules/webpack-merge": { "version": "4.2.1", @@ -235,6 +205,43 @@ "dependencies": { "lodash": "^4.17.5" } + }, + "node-botvac": { + "version": "0.4.2-schedule-write", + "license": "MIT", + "dependencies": { + "axios": "^0.21.1" + } + }, + "node-botvac:./node-botvac": { + "extraneous": true + }, + "node-botvac/node_modules/axios": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", + "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node-botvac/node_modules/follow-redirects": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.3.tgz", + "integrity": "sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } } }, "dependencies": { @@ -376,33 +383,23 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node-botvac": { - "version": "git+ssh://git@github.com/koush/node-botvac.git#9aee6fb4e6963a38a94d77d9c43b85e83e8c90a7", - "from": "node-botvac@github:koush/node-botvac#9aee6fb4e6963a38a94d77d9c43b85e83e8c90a7", + "version": "file:node-botvac", "requires": { - "axios": "^0.18.1" + "axios": "^0.21.1" }, "dependencies": { "axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", + "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" + "follow-redirects": "^1.14.0" } }, "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.3.tgz", + "integrity": "sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==" } } }, diff --git a/plugins/neato/package.json b/plugins/neato/package.json index d2f29747d..762dc9a90 100644 --- a/plugins/neato/package.json +++ b/plugins/neato/package.json @@ -36,6 +36,6 @@ "dependencies": { "axios": "^0.19.2", "crypto-js": "^3.1.9-1", - "node-botvac": "github:koush/node-botvac#9aee6fb4e6963a38a94d77d9c43b85e83e8c90a7" + "node-botvac": "file:./node-botvac" } } diff --git a/plugins/unifi-protect/src/main.ts b/plugins/unifi-protect/src/main.ts index f1cdc04ef..fd512b0a1 100644 --- a/plugins/unifi-protect/src/main.ts +++ b/plugins/unifi-protect/src/main.ts @@ -4,7 +4,7 @@ import { ProtectApiUpdates, ProtectNvrUpdatePayloadCameraUpdate } from "./unifi- const { log, deviceManager, mediaManager } = sdk; -class UnifiCamera extends ScryptedDeviceBase implements Camera, VideoCamera, MotionSensor, Settings { +class UnifiCamera extends ScryptedDeviceBase implements Camera, VideoCamera, MotionSensor { protect: UnifiProtect; activityTimeout: NodeJS.Timeout; @@ -38,10 +38,12 @@ class UnifiCamera extends ScryptedDeviceBase implements Camera, VideoCamera, Mot return mediaManager.createMediaObject(Buffer.from(data), 'image/jpeg'); } async getVideoStream(): Promise { - var u = this.metadata.rtsp; - if (u == null) { - return null; - } + const camera = this.protect.api.Cameras.find(camera => camera.id === this.nativeId); + const rtspChannels = camera.channels.filter(channel => channel.isRtspEnabled); + const rtspChannel = rtspChannels[0]; + + const { rtspAlias } = rtspChannel; + const u = `rtsp://${this.protect.getSetting('ip')}:7447/${rtspAlias}` return mediaManager.createFFmpegMediaObject({ inputArguments: [ @@ -78,23 +80,6 @@ class UnifiCamera extends ScryptedDeviceBase implements Camera, VideoCamera, Mot return video; } - getSetting(key: string): string | number { - return this.storage.getItem(key); - } - async getSettings(): Promise { - return [ - { - key: 'ffmpeg', - title: 'Force FFMPEG', - value: this.getSetting('ffmpeg')?.toString(), - description: "Use ffmpeg instead of built in RTSP decoder.", - type: 'Boolean', - } - ]; - } - async putSetting(key: string, value: string | number) { - this.storage.setItem(key, value.toString()); - } } class UnifiProtect extends ScryptedDeviceBase implements Settings, DeviceProvider { @@ -188,7 +173,7 @@ class UnifiProtect extends ScryptedDeviceBase implements Settings, DeviceProvide await this.api.refreshDevices(); this.api.eventListener?.on('message', this.listener); this.api.eventListener?.on('close', async () => { - this.log.e('Event Listener closed. Reconnecting in 10 seconds.'); + this.console.error('Event Listener closed. Reconnecting in 10 seconds.'); await new Promise(resolve => setTimeout(resolve, 10000)); this.discoverDevices(0); }) @@ -196,7 +181,7 @@ class UnifiProtect extends ScryptedDeviceBase implements Settings, DeviceProvide const devices: Device[] = []; if (!this.api.Cameras) { - this.log.e('Cameras failed to load. Retrying in 10 seconds.'); + this.console.error('Cameras failed to load. Retrying in 10 seconds.'); setTimeout(() => { this.discoverDevices(0); }, 10000); @@ -217,28 +202,15 @@ class UnifiProtect extends ScryptedDeviceBase implements Settings, DeviceProvide camera = await this.api.updateChannels(camera); } - const rtspChannels = camera.channels.filter(channel => channel.isRtspEnabled) - if (!rtspChannels.length) { - log.a(`RTSP is not enabled on the Unifi Camera: ${camera.name}`); - continue; - } - const rtspChannel = rtspChannels[0]; - - const { rtspAlias } = rtspChannel; - const d = { name: camera.name, nativeId: camera.id, interfaces: [ - // ScryptedInterface.Settings, ScryptedInterface.Camera, ScryptedInterface.VideoCamera, ScryptedInterface.MotionSensor, ], type: ScryptedDeviceType.Camera, - metadata: { - rtsp: `rtsp://${ip}:7447/${rtspAlias}` - } }; if (camera.featureFlags.hasChime) { d.interfaces.push(ScryptedInterface.BinarySensor);