UNPKG

maxcube2

Version:

eq-3 Max! Cube interface for homebridge-platform-maxcube

309 lines (260 loc) 8.87 kB
var MaxCubeLowLevel = require('./maxcube-lowlevel'); var MaxCubeCommandParser = require('./maxcube-commandparser'); var MaxCubeCommandFactory = require('./maxcube-commandfactory'); var Promise = require('bluebird'); var util = require('util'); var EventEmitter = require('events').EventEmitter; // Constructor function MaxCube(ip, port) { var self = this; this.maxCubeLowLevel = new MaxCubeLowLevel(ip, port); this.maxCubeLowLevel.connect(); this.waitForCommandType = undefined; this.waitForCommandResolver = undefined; this.initialised = false; this.setMaxListeners(1024); this.commStatus = { duty_cycle: 0, free_memory_slots: 0, } this.metaInfo = { serial: null, firmware_version: null, } this.roomCache = []; this.deviceCache = {}; this.configCache = {}; this.maxCubeLowLevel.on('closed', function () { if( self.waitForCommandResolver ) { self.waitForCommandResolver.reject( 'closed' ); self.waitForCommandType = undefined; self.waitForCommandResolver = undefined; } self.emit('closed'); }); this.maxCubeLowLevel.on('connected', function () { if (!self.initialised) { waitForCommand.call(self, 'M').then(function () { self.emit('connected'); }); } else { self.emit('connected'); } }); this.maxCubeLowLevel.on('error', function( err ) { self.initialised = false; if( self.waitForCommandResolver ) { self.waitForCommandResolver.reject( 'closed' ); self.waitForCommandType = undefined; self.waitForCommandResolver = undefined; } self.emit('error', err); }); this.maxCubeLowLevel.on('command', function (command) { try { var parsedCommand = MaxCubeCommandParser.parse(command.type, command.payload); if (self.waitForCommandType === command.type && self.waitForCommandResolver) { self.waitForCommandResolver.resolve(parsedCommand); self.waitForCommandType = undefined; self.waitForCommandResolver = undefined; } switch (command.type) { case 'H': { self.commStatus.duty_cycle = parsedCommand.duty_cycle; self.commStatus.free_memory_slots = parsedCommand.free_memory_slots; self.metaInfo.serial_number = parsedCommand.serial_number; self.metaInfo.firmware_version = parsedCommand.firmware_version; self.emit('hello', parsedCommand); break; } case 'M': { self.roomCache = parsedCommand.rooms; self.deviceCache = parsedCommand.devices; self.initialised = true; self.emit('meta_data', parsedCommand); break; } case 'L': { self.updateDeviceInfo(parsedCommand); self.emit('device_list', parsedCommand); break; } case 'C': { self.updateDeviceConfig(parsedCommand); self.emit('configuration', parsedCommand); break; } } } catch (e) { self.emit('error', "Problem while parsing the command '" +command.type+"': " + e.stack); } }); this.updateDeviceInfo = function(devices) { if (typeof devices != 'undefined') { for(var i=0; i < devices.length ; i++) { var deviceInfo = devices[i]; var rf = deviceInfo.rf_address; if (typeof self.deviceCache[rf] != 'undefined') { for(var item in deviceInfo) { var val = deviceInfo[item]; self.deviceCache[rf][item] = val; } } } } } this.updateDeviceConfig = function(deviceConfig){ if (typeof deviceConfig != 'undefined'){ var rf = deviceConfig.rf_address; self.configCache[rf] = deviceConfig; } } } util.inherits(MaxCube, EventEmitter); function waitForCommand (commandType) { this.waitForCommandType = commandType; this.waitForCommandResolver = Promise.defer(); return this.waitForCommandResolver.promise; } function send( command, replyCommandType, timeout=0 ) { var self = this; return self.getConnection().then(function () { if( replyCommandType ) { // On commands with expected reply set a timeout if requested self.maxCubeLowLevel.send( command, timeout ); return waitForCommand.call(self, replyCommandType); } else { // Don't set a timeout on commands that don't expect a reply. self.maxCubeLowLevel.send( command, 0 ); return Promise.resolve(); } }); } function checkInitialised() { if (!this.initialised) { throw Error('Maxcube not initialised'); } } MaxCube.prototype.getConnection = function() { return this.maxCubeLowLevel.connect(); } MaxCube.prototype.getCommStatus = function() { return this.commStatus; } MaxCube.prototype.getDeviceStatus = function(rf_address=undefined, timeout=0) { checkInitialised.call(this); return send.call(this, 'l:\r\n', 'L', timeout).then(function (devices) { if (rf_address) { return devices.filter(function(device) { return device.rf_address === rf_address; }); } else { return devices; } }); }; MaxCube.prototype.updateDeviceStatus = function() { checkInitialised.call(this); send.call(this, 'l:\r\n'); }; MaxCube.prototype.getDevices = function() { checkInitialised.call(this); return this.deviceCache; }; MaxCube.prototype.getDevice = function(rf_address) { checkInitialised.call(this); return this.deviceCache[rf_address]; }; MaxCube.prototype.getDeviceInfo = function(rf_address) { checkInitialised.call(this); var deviceInfo = { device_type: null, device_name: null, room_name: null, room_id: null, battery_low: null, panel_locked: null }; var device = this.deviceCache[rf_address]; if (device) { deviceInfo.device_type = device.device_type; deviceInfo.device_name = device.device_name; deviceInfo.battery_low = device.battery_low; deviceInfo.panel_locked= device.panel_locked; if (device.room_id && this.roomCache[device.room_id]) { var room = this.roomCache[device.room_id]; deviceInfo.room_name = room.room_name; deviceInfo.room_id = room.room_id; } } return deviceInfo; }; MaxCube.prototype.getDeviceConfiguration = function(rf_address) { checkInitialised.call(this); var deviceConfig = {} var config = this.configCache[rf_address]; if (config) { for(var item in config) { var val = config[item]; deviceConfig[item] = val; } } return deviceConfig; }; MaxCube.prototype.getRooms = function() { checkInitialised.call(this); return this.roomCache; }; MaxCube.prototype.flushDeviceCache = function() { checkInitialised.call(this); return send.call(this, 'm:\r\n'); }; MaxCube.prototype.resetError = function(rf_address, timeout=0) { checkInitialised.call(this); return send.call(this, MaxCubeCommandFactory.generateResetCommand(rf_address, this.deviceCache[rf_address].room_id), 'S', timeout); }; MaxCube.prototype.sayHello = function(timeout=0) { checkInitialised.call(this); return send.call(this, 'h:\r\n', 'H', timeout).then(function (res) { self.commStatus.duty_cycle = res.duty_cycle; self.commStatus.free_memory_slots = res.free_memory_slots; return true; }); }; MaxCube.prototype.setTemperature = function(rf_address, degrees, mode, untilDate, timeout=0) { checkInitialised.call(this); var self = this; degrees = Math.max(2, degrees); var command = MaxCubeCommandFactory.generateSetTemperatureCommand (rf_address, this.deviceCache[rf_address].room_id, mode || 'MANUAL', degrees, untilDate); return send.call(this, command, 'S', timeout).then(function (res) { self.commStatus.duty_cycle = res.duty_cycle; self.commStatus.free_memory_slots = res.free_memory_slots; return res.accepted; }); }; MaxCube.prototype.setSchedule = function(rf_address, room_id, weekday, temperaturesArray, timesArray, timeout=0) { // weekday: 0=mo,1=tu,..,6=su // temperaturesArray: [19.5,21,..] degrees Celsius (max 7) // timesArray: ['HH:mm',..] 24h format (max 7, same amount as temperatures) // the first time will be the time (from 00:00 to timesArray[0]) that the first temperature is active. Last possibe time of the day: 00:00 checkInitialised.call(this); var self = this; var command = MaxCubeCommandFactory.generateSetDayProgramCommand (rf_address, room_id, weekday, temperaturesArray, timesArray); return send.call(this, command, 'S', timeout).then(function (res) { self.commStatus.duty_cycle = res.duty_cycle; self.commStatus.free_memory_slots = res.free_memory_slots; return res.accepted; }); }; MaxCube.prototype.close = function() { this.maxCubeLowLevel.close(); }; MaxCube.prototype.disconnect = function() { send.call(this, 'q:\r\n'); }; module.exports = MaxCube;