mirror of
https://github.com/koush/scrypted.git
synced 2026-02-12 18:12:04 +00:00
myq: migrate to org https://github.com/scryptedapp/myq
This commit is contained in:
4
plugins/myq/.gitignore
vendored
4
plugins/myq/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
.DS_Store
|
||||
out/
|
||||
node_modules/
|
||||
dist/
|
||||
@@ -1,4 +0,0 @@
|
||||
.DS_Store
|
||||
out/
|
||||
node_modules/
|
||||
dist/*.map
|
||||
23
plugins/myq/.vscode/launch.json
vendored
23
plugins/myq/.vscode/launch.json
vendored
@@ -1,23 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Scrypted Debugger",
|
||||
"address": "${config:scrypted.debugHost}",
|
||||
"port": 10081,
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"**/plugin-remote-worker.*",
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"preLaunchTask": "scrypted: deploy+debug",
|
||||
"sourceMaps": true,
|
||||
"localRoot": "${workspaceFolder}/out",
|
||||
"remoteRoot": "/plugin/",
|
||||
"type": "node"
|
||||
}
|
||||
]
|
||||
}
|
||||
4
plugins/myq/.vscode/settings.json
vendored
4
plugins/myq/.vscode/settings.json
vendored
@@ -1,4 +0,0 @@
|
||||
|
||||
{
|
||||
"scrypted.debugHost": "127.0.0.1",
|
||||
}
|
||||
20
plugins/myq/.vscode/tasks.json
vendored
20
plugins/myq/.vscode/tasks.json
vendored
@@ -1,20 +0,0 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "scrypted: deploy+debug",
|
||||
"type": "shell",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "silent",
|
||||
"focus": false,
|
||||
"panel": "shared",
|
||||
"showReuseMessage": true,
|
||||
"clear": false
|
||||
},
|
||||
"command": "npm run scrypted-vscode-launch ${config:scrypted.debugHost}",
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# MyQ Garage Plugin for Scrypted
|
||||
The MyQ Garage Plugin brings MyQ garage door support into Scrypted.
|
||||
|
||||
Currently, no other MyQ devices are supported.
|
||||
1367
plugins/myq/package-lock.json
generated
1367
plugins/myq/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"name": "@scrypted/myq",
|
||||
"version": "0.1.44",
|
||||
"description": "A MyQ Garage plugin for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
"prescrypted-setup-project": "scrypted-package-json",
|
||||
"build": "scrypted-webpack",
|
||||
"prepublishOnly": "NODE_ENV=production scrypted-webpack",
|
||||
"prescrypted-vscode-launch": "scrypted-webpack",
|
||||
"scrypted-vscode-launch": "scrypted-deploy-debug",
|
||||
"scrypted-deploy-debug": "scrypted-deploy-debug",
|
||||
"scrypted-debug": "scrypted-debug",
|
||||
"scrypted-deploy": "scrypted-deploy",
|
||||
"scrypted-readme": "scrypted-readme",
|
||||
"scrypted-package-json": "scrypted-package-json"
|
||||
},
|
||||
"keywords": [
|
||||
"myq",
|
||||
"scrypted",
|
||||
"plugin"
|
||||
],
|
||||
"scrypted": {
|
||||
"name": "MyQ Garage Controller",
|
||||
"type": "DeviceProvider",
|
||||
"realfs": true,
|
||||
"interfaces": [
|
||||
"DeviceProvider",
|
||||
"Settings"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/lodash": "^4.14.172"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hjdhjd/myq": "^6.0.7",
|
||||
"axios": "^0.27.2",
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
|
||||
import sdk, { ScryptedDeviceBase, DeviceProvider, Device, ScryptedDeviceType, Entry, Refresh, OnOff, Settings, Setting, EntrySensor, ScryptedInterface, Battery, Online } from '@scrypted/sdk';
|
||||
const { log } = sdk;
|
||||
import { myQApi, myQDevice, myQDeviceInterface } from '@hjdhjd/myq';
|
||||
import throttle from 'lodash/throttle';
|
||||
|
||||
const { deviceManager } = sdk;
|
||||
|
||||
function isValidGarageDoor(device: myQDeviceInterface) {
|
||||
//return device_type === 'wifigaragedooropener' || device_type === 'virtualgaragedooropener' || device_type === 'garagedooropener';
|
||||
return device.device_family === 'garagedoor'
|
||||
}
|
||||
|
||||
class GarageController extends ScryptedDeviceBase implements DeviceProvider, Settings, Battery {
|
||||
devices = new Map<string, GarageDoor>();
|
||||
account: myQApi;
|
||||
loginTokenTime: number;
|
||||
start: Promise<void>;
|
||||
throttleRefresh = throttle(async () => {
|
||||
try {
|
||||
await this.discoverDevices(0);
|
||||
await this.updateStates();
|
||||
}
|
||||
catch (e) {
|
||||
console.error('refresh failed', e);
|
||||
}
|
||||
}, 60000, {
|
||||
leading: true,
|
||||
trailing: true,
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.start = this.discoverDevices(0);
|
||||
this.start.then(() => this.updateStates());
|
||||
this.start.catch(e => console.error('discovery error', e));
|
||||
}
|
||||
|
||||
async getSettings(): Promise<Setting[]> {
|
||||
return [
|
||||
{
|
||||
title: 'Email',
|
||||
key: 'email',
|
||||
value: localStorage.getItem('email'),
|
||||
},
|
||||
{
|
||||
title: 'Password',
|
||||
type: 'password',
|
||||
key: 'password',
|
||||
value: localStorage.getItem('password'),
|
||||
}
|
||||
];
|
||||
}
|
||||
async putSetting(key: string, value: string | number | boolean) {
|
||||
localStorage.setItem(key, value.toString());
|
||||
}
|
||||
|
||||
async getDevice(nativeId: string) {
|
||||
await this.start;
|
||||
if (!this.devices[nativeId])
|
||||
this.devices[nativeId] = new GarageDoor(this, this.account.devices.find(d => d.serial_number === nativeId)!);
|
||||
this.devices[nativeId]?.refresh();
|
||||
return this.devices[nativeId];
|
||||
}
|
||||
|
||||
async releaseDevice(id: string, nativeId: string) {
|
||||
this.console.info(`Device with serial number '${nativeId}' was removed`)
|
||||
}
|
||||
|
||||
async discoverDevices(duration: number) {
|
||||
if (!this.account) {
|
||||
const email = localStorage.getItem('email');
|
||||
const password = localStorage.getItem('password');
|
||||
if (!email || !password) {
|
||||
throw new Error('Not logged in.');
|
||||
}
|
||||
|
||||
this.account = new myQApi(email, password, console);
|
||||
}
|
||||
|
||||
await this.account.refreshDevices();
|
||||
console.log(this.account.devices);
|
||||
|
||||
const devices: Device[] = [];
|
||||
for (const device of this.account.devices) {
|
||||
if (!isValidGarageDoor(device)) {
|
||||
console.log('ignoring device', device);
|
||||
continue;
|
||||
}
|
||||
|
||||
const parent = this.account.devices.find((value: any) => value.serial_number === device.parent_device_id) as any;
|
||||
const interfaces = [ScryptedInterface.Entry, ScryptedInterface.EntrySensor, ScryptedInterface.Refresh, ScryptedInterface.Online];
|
||||
|
||||
if (device.state.dps_low_battery_mode !== undefined)
|
||||
interfaces.push(ScryptedInterface.Battery);
|
||||
|
||||
devices.push({
|
||||
name: device.name,
|
||||
nativeId: device.serial_number,
|
||||
interfaces,
|
||||
type: ScryptedDeviceType.Garage,
|
||||
info: {
|
||||
manufacturer: parent?.state?.brand_name ?? 'MyQ',
|
||||
serialNumber: device.serial_number,
|
||||
firmware: parent?.state?.firmware_version
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await deviceManager.onDevicesChanged({
|
||||
devices,
|
||||
});
|
||||
}
|
||||
|
||||
async updateStates() {
|
||||
for (const device of this.account.devices) {
|
||||
if (!isValidGarageDoor(device)) {
|
||||
console.log('ignoring device', device);
|
||||
continue;
|
||||
}
|
||||
|
||||
const d = await this.getDevice(device.serial_number) as GarageDoor;
|
||||
d.entryOpen = device.state.door_state !== 'closed';
|
||||
|
||||
// there's no battery level, so set it to full or empty.
|
||||
// consumers of the battery level can decide when to alert on low battery.
|
||||
if (device.state.dps_low_battery_mode !== undefined)
|
||||
d.batteryLevel = device.state.dps_low_battery_mode ? 0 : 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GarageDoor extends ScryptedDeviceBase implements Entry, Refresh, EntrySensor, Online {
|
||||
controller: GarageController;
|
||||
|
||||
constructor(controller: GarageController, public device: myQDevice) {
|
||||
super(device.serial_number)
|
||||
this.controller = controller;
|
||||
this.online = device.state.online;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
async closeEntry() {
|
||||
this.controller.account.execute(this.device, 'close');
|
||||
this.refreshForLongRunningOperation();
|
||||
}
|
||||
async openEntry() {
|
||||
this.controller.account.execute(this.device, 'open');
|
||||
this.refreshForLongRunningOperation();
|
||||
}
|
||||
async getRefreshFrequency() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
refreshForLongRunningOperation() {
|
||||
// refreshf for 10 minutes.
|
||||
for (let i = 0; i < 10; i++) {
|
||||
setTimeout(() => this.refresh(), i * 60000);
|
||||
}
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
this.controller.throttleRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
// class GarageLight extends ScryptedDeviceBase implements OnOff, Refresh {
|
||||
// controller: GarageController;
|
||||
// info: Device;
|
||||
|
||||
// constructor(controller, info: Device) {
|
||||
// super(info.nativeId);
|
||||
// this.controller = controller;
|
||||
// this.info = info;
|
||||
// this.refresh();
|
||||
// }
|
||||
|
||||
// async turnOn() {
|
||||
// // this.lightStateCommand(1);
|
||||
// }
|
||||
// async turnOff() {
|
||||
// // this.lightStateCommand(0);
|
||||
// }
|
||||
// async refresh() {
|
||||
// };
|
||||
// async getRefreshFrequency() {
|
||||
// return 60;
|
||||
// };
|
||||
// }
|
||||
|
||||
export default new GarageController();
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "ES2021",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "Node16",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user