Controller.prototype.setNvParams = function (net) { // net: { panId, channelList, precfgkey, precfgkeysEnable, startoptClearState } net = net || {}; proving.object(net, 'opts.net should be an object.'); _.forEach(net, function (val, param) { switch (param) { case 'panId': proving.number(val, 'net.panId should be a number.'); nvParams.panId.value = [ val & 0xFF, (val >> 8) & 0xFF ]; break; case 'precfgkey': if (!_.isArray(val) || val.length !== 16) throw new TypeError('net.precfgkey should be an array with 16 uint8 integers.'); nvParams.precfgkey.value = val; break; case 'precfgkeysEnable': proving.boolean(val, 'net.precfgkeysEnable should be a bool.'); nvParams.precfgkeysEnable.value = val ? [ 0x01 ] : [ 0x00 ]; break; case 'startoptClearState': proving.boolean(val, 'net.startoptClearState should be a bool.'); nvParams.startupOption.value = val ? [ 0x02 ] : [ 0x00 ]; break; case 'channelList': proving.array(val, 'net.channelList should be an array.'); var chList = 0; _.forEach(val, function (ch) { if (ch >= 11 && ch <= 26) chList = chList | ZSC.ZDO.channelMask['CH' + ch]; }); nvParams.channelList.value = [ chList & 0xFF, (chList >> 8) & 0xFF, (chList >> 16) & 0xFF, (chList >> 24) & 0xFF ]; break; default: throw new TypeError('Unkown argument: ' + param + '.'); } }); };
/*************************************************************************************************/ /*** ZShepherd Class ***/ /*************************************************************************************************/ function ZShepherd(path, opts) { // opts: { sp: {}, net: {}, dbPath: 'xxx' } var self = this, spCfg = {}; EventEmitter.call(this); opts = opts || {}; proving.string(path, 'path should be a string.'); proving.object(opts, 'opts should be an object if gieven.'); spCfg.path = path; spCfg.options = opts.hasOwnProperty('sp') ? opts.sp : { baudrate: 115200, rtscts: true }; /***************************************************/ /*** Protected Members ***/ /***************************************************/ this._startTime = 0; this._enabled = false; this._zApp = []; this._mounting = false; this._mountQueue = []; this.controller = new Controller(this, spCfg); // controller is the main actor this.controller.setNvParams(opts.net); this.af = null; this._dbPath = opts.dbPath; if (!this._dbPath) { // use default this._dbPath = __dirname + '/database/dev.db'; // create default db folder if not there try { fs.statSync(__dirname + '/database'); } catch (e) { fs.mkdirSync(__dirname + '/database'); } } this._devbox = new Objectbox(this._dbPath); this.acceptDevIncoming = function (devInfo, callback) { // Override at will. setImmediate(function () { var accepted = true; callback(null, accepted); }); }; /***************************************************/ /*** Event Handlers (Ind Event Bridges) ***/ /***************************************************/ eventHandlers.attachEventHandlers(this); this.controller.on('permitJoining', function (time) { self.emit('permitJoining', time); }); this.on('_ready', function () { self._startTime = Math.floor(Date.now()/1000); setImmediate(function () { self.emit('ready'); }); }); this.on('ind:incoming', function (dev) { var endpoints = []; _.forEach(dev.epList, function (epId) { endpoints.push(dev.getEndpoint(epId)); }); self.emit('ind', { type: 'devIncoming', endpoints: endpoints, data: dev.getIeeeAddr() }); }); this.on('ind:interview', function (dev, status) { self.emit('ind', { type: 'devInterview', status: status, data: dev }); }); this.on('ind:leaving', function (epList, ieeeAddr) { self.emit('ind', { type: 'devLeaving', endpoints: epList, data: ieeeAddr }); }); this.on('ind:changed', function (ep, notifData) { self.emit('ind', { type: 'devChange', endpoints: [ ep ], data: notifData }); }); this.on('ind:reported', function (ep, cId, attrs) { var cIdString = zclId.cluster(cId), notifData = { cid: '', data: {} }; self._updateFinalizer(ep, cId, attrs, true); cIdString = cIdString ? cIdString.key : cId; notifData.cid = cIdString; _.forEach(attrs, function (rec) { // { attrId, dataType, attrData } var attrIdString = zclId.attr(cIdString, rec.attrId); attrIdString = attrIdString ? attrIdString.key : rec.attrId; notifData.data[attrIdString] = rec.attrData; }); self.emit('ind', { type: 'attReport', endpoints: [ ep ], data: notifData }); }); this.on('ind:status', function (dev, status) { var endpoints = []; _.forEach(dev.epList, function (epId) { endpoints.push(dev.getEndpoint(epId)); }); self.emit('ind', { type: 'devStatus', endpoints: endpoints, data: status }); }); }