UNPKG

homebridge-levoit-humidifiers

Version:
235 lines 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BypassMethod = void 0; const axios_1 = __importDefault(require("axios")); const async_lock_1 = __importDefault(require("async-lock")); const crypto_1 = __importDefault(require("crypto")); const deviceTypes_1 = __importDefault(require("./deviceTypes")); const VeSyncFan_1 = __importDefault(require("./VeSyncFan")); var BypassMethod; (function (BypassMethod) { BypassMethod["STATUS"] = "getHumidifierStatus"; BypassMethod["MODE"] = "setHumidityMode"; BypassMethod["NIGHT_LIGHT_BRIGHTNESS"] = "setNightLightBrightness"; BypassMethod["DISPLAY"] = "setDisplay"; BypassMethod["SWITCH"] = "setSwitch"; BypassMethod["HUMIDITY"] = "setTargetHumidity"; BypassMethod["MIST_LEVEL"] = "setVirtualLevel"; BypassMethod["LEVEL"] = "setLevel"; BypassMethod["LIGHT_STATUS"] = "setLightStatus"; BypassMethod["DRYING_MODE"] = "setDryingMode"; })(BypassMethod = exports.BypassMethod || (exports.BypassMethod = {})); const lock = new async_lock_1.default(); class VeSync { constructor(email, password, config, debugMode, log) { var _a; this.email = email; this.password = password; this.config = config; this.debugMode = debugMode; this.log = log; this.VERSION = '4.1.70'; this.FULL_VERSION = `VeSync ${this.VERSION} build15`; this.AGENT = `VeSync/${this.VERSION} (iPhone; iOS 17.2.1; Humidifier/5.00)`; this.TIMEZONE = 'America/New_York'; this.OS = 'iOS 17.2.1'; this.BRAND = 'iPhone 15 Pro'; this.LANG = 'en'; this.AXIOS_OPTIONS = { baseURL: 'https://smartapi.vesync.com', timeout: ((_a = this.config.options) === null || _a === void 0 ? void 0 : _a.apiTimeout) || 15000, }; } generateDetailBody() { return { appVersion: this.FULL_VERSION, phoneBrand: this.BRAND, traceId: Date.now(), phoneOS: this.OS, }; } generateBody(includeAuth = false) { return { acceptLanguage: this.LANG, timeZone: this.TIMEZONE, ...(includeAuth ? { accountID: this.accountId, token: this.token, } : {}), }; } generateV2Body(fan, method, data = {}) { return { method: 'bypassV2', debugMode: false, deviceRegion: fan.region, cid: fan.cid, configModule: fan.configModule, payload: { data: { ...data, }, method, source: 'APP', }, }; } async sendCommand(fan, method, body = {}) { return lock.acquire('api-call', async () => { var _a, _b; if (!this.api) { throw new Error('The user is not logged in!'); } this.debugMode.debug('[SEND COMMAND]', `Sending command ${method} to ${fan.name}`, `with (${JSON.stringify(body)})...`); const response = await this.api.put('cloud/v2/deviceManaged/bypassV2', { ...this.generateV2Body(fan, method, body), ...this.generateDetailBody(), ...this.generateBody(true), }); // Explicitly fail if device is offline if (response.data.msg == 'device offline') { this.log.error('VeSync cannot communicate with humidifier! Check the VeSync App.'); if ((_a = this.config.options) === null || _a === void 0 ? void 0 : _a.showOffWhenDisconnected) { return false; } else { throw new Error('Device was unreachable. Ensure it is plugged in and connected to WiFi.'); } } if (!(response === null || response === void 0 ? void 0 : response.data)) { this.debugMode.debug('[SEND COMMAND]', 'No response data!! JSON:', JSON.stringify(response === null || response === void 0 ? void 0 : response.data)); } const isSuccess = ((_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.code) === 0; if (!isSuccess) { this.debugMode.debug('[SEND COMMAND]', `Failed to send command ${method} to ${fan.name}`, `with (${JSON.stringify(body)})!`, `Response: ${JSON.stringify(response === null || response === void 0 ? void 0 : response.data)}`); } else { this.debugMode.debug('[SEND COMMAND]', `Successfully sent command ${method} to ${fan.name}`, `with (${JSON.stringify(body)})!`, `Response: ${JSON.stringify(response.data)}`); } return isSuccess; }); } async getDeviceInfo(fan) { return lock.acquire('api-call', async () => { var _a; if (!this.api) { throw new Error('The user is not logged in!'); } this.debugMode.debug('[GET DEVICE INFO]', 'Getting device info...'); const response = await this.api.post('cloud/v2/deviceManaged/bypassV2', { ...this.generateV2Body(fan, BypassMethod.STATUS), ...this.generateDetailBody(), ...this.generateBody(true), }); this.debugMode.debug('[DEVICE INFO]', JSON.stringify(response.data)); // Explicitly fail if device is offline if (response.data.msg == 'device offline') { this.log.error('VeSync cannot communicate with humidifier! Check the VeSync App.'); if ((_a = this.config.options) === null || _a === void 0 ? void 0 : _a.showOffWhenDisconnected) { return false; } else { throw new Error('Device was unreachable. Ensure it is plugged in and connected to WiFi.'); } } if (!(response === null || response === void 0 ? void 0 : response.data)) { this.debugMode.debug('[GET DEVICE INFO]', 'No response data!! JSON:', JSON.stringify(response === null || response === void 0 ? void 0 : response.data)); } return response.data; }); } async startSession() { this.debugMode.debug('[START SESSION]', 'Starting auth session...'); const firstLoginSuccess = await this.login(); setInterval(this.login.bind(this), 1000 * 60 * 55); // Refresh token every 55 minutes return firstLoginSuccess; } async login() { return lock.acquire('api-call', async () => { if (!this.email || !this.password) { throw new Error('Email and password are required'); } this.debugMode.debug('[LOGIN]', 'Logging in...'); const pwdHashed = crypto_1.default .createHash('md5') .update(this.password) .digest('hex'); const response = await axios_1.default.post('cloud/v1/user/login', { email: this.email, password: pwdHashed, devToken: '', userType: 1, method: 'login', token: '', ...this.generateDetailBody(), ...this.generateBody(), }, { ...this.AXIOS_OPTIONS, }); if (!(response === null || response === void 0 ? void 0 : response.data)) { this.debugMode.debug('[LOGIN]', 'No response data!! JSON:', JSON.stringify(response === null || response === void 0 ? void 0 : response.data)); return false; } const { result } = response.data; const { token, accountID } = result !== null && result !== void 0 ? result : {}; if (!token || !accountID) { this.debugMode.debug('[LOGIN]', 'The authentication failed!! JSON:', JSON.stringify(response.data)); return false; } this.debugMode.debug('[LOGIN]', 'Authentication was successful'); this.accountId = accountID; this.token = token; this.api = axios_1.default.create({ ...this.AXIOS_OPTIONS, headers: { 'content-type': 'application/json', 'accept-language': this.LANG, accountid: this.accountId, 'user-agent': this.AGENT, appversion: this.FULL_VERSION, tz: this.TIMEZONE, tk: this.token, }, }); return true; }); } async getDevices() { return lock.acquire('api-call', async () => { var _a, _b, _c; if (!this.api) { this.log.error('The user is not logged in!'); return []; } const response = await this.api.post('cloud/v2/deviceManaged/devices', { method: 'devices', pageNo: 1, pageSize: 1000, ...this.generateDetailBody(), ...this.generateBody(true), }); if (!(response === null || response === void 0 ? void 0 : response.data)) { this.debugMode.debug('[GET DEVICES]', 'No response data!! JSON:', JSON.stringify(response === null || response === void 0 ? void 0 : response.data)); return []; } if (!Array.isArray((_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.result) === null || _b === void 0 ? void 0 : _b.list)) { this.debugMode.debug('[GET DEVICES]', 'No list found!! JSON:', JSON.stringify(response.data)); return []; } const { list } = (_c = response.data.result) !== null && _c !== void 0 ? _c : { list: [] }; this.debugMode.debug('[GET DEVICES]', 'Device List -> JSON:', JSON.stringify(list)); const devices = list .filter(({ deviceType, type }) => !!deviceTypes_1.default.find(({ isValid }) => isValid(deviceType)) && type === 'wifi-air') .map(VeSyncFan_1.default.fromResponse(this)); return devices; }); } } exports.default = VeSync; //# sourceMappingURL=VeSync.js.map