UNPKG

homebridge-starline

Version:
192 lines (173 loc) 4.85 kB
let request = require('co-request'); module.exports = class StarlineRemote { /** * Constructor * * @param {Object} device */ constructor(device) { this.name = device.config.name || 'StarlineVehicle'; this.username = device.config.username || ''; this.password = device.config.password || ''; this.interval = device.config.interval || 5000; this.tz = device.config.tz || 180; this.debug = device.debug; this.log = device.log; this.updateAccessoryInfo = device.updateAccessoryInfo.bind(device); this.device = device; this.currentState = device; this.turningOn = null; this.turningOff = null; this.checkingState = null; this.remote = new RemoteService(this); this.checkState(); } async checkState() { if (this.checkingState) { return Promise.reject('Checking state is in progress'); } // this.debug('Checking state'); this.checkingState = true; const state = await this.remote.getState(); if (state) { this.currentState = state; this.updateAccessoryInfo(state); } else { this.log('Checking failed'); } this.checkingState = false; await this._delay(this.interval); this.checkState(); } async executeCommand(...args) { return /* await */ this.remote.executeCommand(this.currentState.device_id, ...args); } /** * Private: Create a delay * * @param {Number} ms * @return {Promise} */ _delay(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } } class RemoteService { constructor(config) { this.username = config.username; this.password = config.password; this.name = config.name; this.log = config.log; this.debug = config.debug; this.prefix = `https://starline-online.ru`; this.cookies = null; this.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0', // 'Accept': 'application/json, text/javascript, */*; q=0.01', // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } } async request(obj) { if (!this.cookies) { await this.authentication(); } let result = await request({ ...obj, headers: { ...obj.headers, Cookie: this.cookies } }); if (result.statusCode === 403) { await this.authentication(); return await request({ ...obj, headers: { ...obj.headers, Cookie: this.cookies } }); } return result; } async authentication() { try { const result = await request({ uri: `${this.prefix}/rest/security/login`, method: 'POST', form: { 'username': this.username, 'password': this.password, 'rememberMe': true }, headers: this.headers }); if (result.statusCode === 200) { this.cookies = this.parseCookies(result.headers['set-cookie']); return true; } this.debug(`Authorization request returns ${result.statusCode}, body: ${result.body}`); return false; } catch (e) { this.log('Authorization failed', e); } } parseCookies(rawData) { const result = []; rawData.forEach(raw => { // if (!raw.includes('PHPSESSID', 'userAgentId')) return; result.push(raw.split(';')[0]); }); return result.join('; '); } async getState() { try { const result = await this.request({ uri: `${this.prefix}/device?tz=${this.tz || 180}&_=${(new Date()).getTime()}`, method: 'GET', headers: { ...this.headers, }, json: true }); if (result.statusCode === 200) { const devices = result.body.answer.devices; const device = devices.find((element) => { if (element.alias === this.name) { return true; } }); if (!device) { throw new Error('Device by specified name not found'); } return device; } this.debug(`GetState request returns ${result.statusCode}, body: ${result.body}`); } catch (e) { this.log(`Cannot check state: ${e}`); } } async executeCommand(deviceId, key, value) { try { const result = await this.request({ uri: `${this.prefix}/device/${deviceId}/executeCommand`, method: 'POST', form: { 'value': value ? 1 : 0, 'action': key, 'password': '' }, headers: { ...this.headers, Cookie: this.cookies } }); return result.statusCode === 204; } catch (e) { this.log(`Cannot execute command ${e}`); } } }