iobroker.mercury
Version:
Receiving data from electricity meters Mercury
716 lines (689 loc) • 29.9 kB
JavaScript
;
const utils = require('@iobroker/adapter-core');
const fs = require('fs');
const net = require('net');
const m = require('./lib/mercury.js');
const path = require('path');
const SerialPort = require('serialport');
const InterByteTimeout = require('@serialport/parser-inter-byte-timeout');
let mercury, serial;
let adapter, _callback, devices = [], dataFile = 'devices.json', pollAllowed = false, isOnline = false, iter = 0, firstStart = true,
fastPollingTime, slowPollingTime, timeout = null, reconnectTimeOut = null, CRCTimeOut = null, timeoutPoll = null, isPoll = false, queueCmd = null, endTime, startTime;
let parser, poll_index = 0;
const msg = {cmd: [], protocol: null, addr: 0, pwd: [], user: 1};
function startAdapter(options){
return adapter = utils.adapter(Object.assign({}, options, {
systemConfig: true,
name: 'mercury',
ready: main,
unload: (callback) => {
timeout && clearTimeout(timeout);
timeoutPoll && clearTimeout(timeoutPoll);
CRCTimeOut && clearTimeout(CRCTimeOut);
reconnectTimeOut && clearTimeout(reconnectTimeOut);
if (parser) parser.destroy();
if (serial) serial.close;
if (mercury) mercury.destroy();
try {
adapter.log.debug('cleaned everything up...');
callback();
} catch (e) {
callback();
}
},
stateChange: (id, state) => {
if (id && state && !state.ack){
adapter.log.debug(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
const arr = id.split('.');
const sn = parseInt(arr[2]);
id = arr[arr.length - 1];
if (id === 'RAW'){
const index = getDeviceIndexAtSn(sn);
let addr = devices[index].conf.addr.val;
if (devices[index].conf.protocol.val === 1) addr = addrToArray(devices[index].conf.addr.val);
const val = state.val.split(' ').map((x) => {
return parseInt(x, 16);
});
const cmd = {
cmd: [].concat(addr, val),
cb: (response) => {
adapter.log.debug('Ответ получен - ' + JSON.stringify(response));
adapter.setState(sn + '.RAW', {val: JSON.stringify(response), ack: true});
}
};
if (isPoll){
adapter.log.debug('RAW - Идет опрос счетчика, добавляем команду в очередь');
queueCmd = cmd;
} else {
sendQueue(cmd);
}
}
}
},
message: obj => {
if (typeof obj === 'object' && obj.command){
adapter.log.debug(`message ******* ${JSON.stringify(obj)}`);
if (obj.command === 'getDevices'){
obj.callback && adapter.sendTo(obj.from, obj.command, devices, obj.callback);
}
if (obj.command === 'getOptions'){
obj.callback && adapter.sendTo(obj.from, obj.command, m.options, obj.callback);
}
if (obj.command === 'findDevice'){
if (isOnline){
_callback = (e) => {
if (e) adapter.log.error('findDevice ERROR ---' + JSON.stringify(e));
pollAllowed = true;
obj.callback && adapter.sendTo(obj.from, obj.command, e ? {error: e} :devices, obj.callback);
};
findDevice(obj.message);
} else {
obj.callback && adapter.sendTo(obj.from, obj.command, {error: 'No connection to the device'}, obj.callback);
}
}
if (obj.command === 'updateDevices'){
if (obj.message.conf.pwd && obj.message.conf.pwd.val !== null){
obj.message.conf.pwd.val = obj.message.conf.pwd.val.toString().split('');
}
adapter.log.debug('updateDevices');
devices[obj.message.index].conf = obj.message.conf;
devices[obj.message.index].conf.model.name = m.options.model[obj.message.conf.model.val].desc;
saveDevices();
obj.callback && adapter.sendTo(obj.from, obj.command, devices, obj.callback);
}
if (obj.command === 'deleteDevice'){
pollAllowed = false;
devices.splice(obj.message.index, 1);
saveDevices();
pollAllowed = true;
obj.callback && adapter.sendTo(obj.from, obj.command, devices, obj.callback);
}
if (obj.command === 'getSerialPorts'){
listSerial().then((ports) => {
adapter.log.debug('List of ports: ' + JSON.stringify(ports));
obj.callback && adapter.sendTo(obj.from, obj.command, ports, obj.callback);
});
}
} else {
adapter.log.debug(`message x ${obj.command}`);
}
}
}));
}
function poll(){
timeoutPoll && clearTimeout(timeoutPoll);
if (pollAllowed){
iter = 0;
isPoll = true;
let nameArray = '';
//for (let index = 0; index < devices.length; index++) {
if (poll_index >= devices.length) poll_index = 0;
msg.protocol = devices[poll_index].conf.protocol.val;
adapter.log.debug('Опрашиваем счетчик # ' + poll_index + ' с адресом: ' + devices[poll_index].conf.addr.val);
openChannel(poll_index, msg, (e) => {
if (!e){
if (endTime - startTime > slowPollingTime){
startTime = new Date().getTime();
nameArray = 'poll';
} else {
if (firstStart){
pollAllowed = false;
nameArray = 'first';
} else {
nameArray = 'fastpoll';
}
}
adapter.log.debug('slowPollingTime = ' + (endTime - startTime));
sendPolling(poll_index, msg.protocol, nameArray);
} else {
adapter.log.error(e);
}
});
//}
}
}
function sendPolling(index, protocol, nameArray, cb){
try {
if (devices.length > 0){
let addr = devices[index].conf.addr.val;
if (protocol === 1) addr = addrToArray(devices[index].conf.addr.val);
msg.cmd = [].concat(addr, m.options.protocol[protocol][nameArray][iter].code, m.options.protocol[protocol][nameArray][iter].cmd);
adapter.log.debug('-----------------------------------------------------------------------------------------------------');
adapter.log.debug('Получаем информацию из массива (' + nameArray + ') - ' + m.options.protocol[protocol][nameArray][iter].desc + '. cmd = ' + JSON.stringify(msg.cmd) + ' / iter=' + iter);
send(msg, (response) => {
adapter.log.debug(response.length > 0 ? 'Ответ получен, парсим:' :'Нет ответа на команду, читаем следующую.');
if (response.length > 0) devices = m.options.protocol[protocol][nameArray][iter].func(devices, index, msg.cmd, response);
iter++;
if (iter > m.options.protocol[protocol][nameArray].length - 1){
iter = 0;
if (nameArray === 'first') firstStart = false;
if (queueCmd){
sendQueue(queueCmd);
}
pollAllowed = true;
adapter.log.debug('# Все данные прочитали, сохраняем полученные данные. #'/* + JSON.stringify(devices)*/);
isPoll = false;
setObjects(index);
timeoutPoll = setTimeout(() => {
endTime = new Date().getTime();
poll_index++;
poll();
}, fastPollingTime);
} else {
sendPolling(index, protocol, nameArray, cb);
}
});
}
} catch (e) {
adapter.log.error('Error: sendPolling ' + e);
}
}
function sendQueue(cmd){
send(cmd, (response) => {
queueCmd = null;
cmd.cb && cmd.cb(response);
});
}
function findDevice(_msg){
adapter.log.debug('findDevice msg ---' + JSON.stringify(_msg)); //{"addr":"","model":"230"}
pollAllowed = false;
msg.cmd = [];
msg.addr = _msg.addr.toString();
msg.user = parseInt(_msg.user, 10);
msg.model = parseInt(_msg.model, 10);
msg.protocol = m.options.model[_msg.model].type;
msg.modelname = m.options.model[_msg.model].desc;
msg.pwd = (_msg.pwd.toString().split('')).map((x) => {
return parseInt(x, 10);
});
if (msg.model && !msg.addr && msg.protocol === 2){
adapter.log.debug('Поиск трехфазного с адресом - 0');
openChannel(null, msg, (e) => {
if (!e){
msg.cmd = [0x00, 0x08, 0x05]; //Запрос с нулевым адресом 3 фазного счетчика
send(msg);
} else {
_callback('Error opening communication channel');
}
});
} else if (msg.model && msg.addr){
if (msg.protocol === 1){
if (parseInt(msg.model, 10) === 200){
msg.addr = msg.addr.slice(msg.addr.length - 6, msg.addr.length);
} else {
msg.addr = msg.addr.slice(msg.addr.length - 8, msg.addr.length);
}
msg.cmd = msg.cmd.concat(addrToArray(msg.addr), [0x2f]);
adapter.log.debug('----------------------------------------------------------------------------');
adapter.log.debug('Поиск однофазного с адресом - ' + msg.addr);
send(msg);
}
if (msg.protocol === 2){
if (msg.addr.length > 2){
msg.addr = parseInt(msg.addr.substr(msg.addr.length - 3));
if (parseInt(msg.addr, 10) > 240){
msg.addr = parseInt(msg.addr.toString().substr(msg.addr.toString().length - 2));
}
}
msg.addr = parseInt(msg.addr, 10);
adapter.log.debug('Поиск треxфазного с адресом - ' + msg.addr);
openChannel(null, msg, (e) => {
if (!e){
msg.cmd = [msg.addr, 0x08, 0x05]; //Запрос 3 фазного
send(msg);
} else {
_callback('Error opening communication channel');
}
});
}
} else {
_callback('Invalid data specified');
}
}
function parseFindPacket(response, msg, cb){ //response, cmd, protocol
if (msg.protocol === 1){
adapter.log.debug('Парсим ответ от однофазного счетчика');
if (/*response[0] === 0 && */response[4] === 47){ //hex 2f //Ответ на поиск 1 фазного
const addrInt = response.readUInt32BE(0); //0 14 31 155
const index = getDeviceIndexAtAddr(addrInt);
devices[index] = m.template[msg.protocol];
devices[index].conf.addr.val = addrInt;
devices[index].conf.user.val = 2;
devices[index] = m.template[msg.protocol];
devices[index].conf.protocol.val = msg.protocol;
devices[index].conf.model.name = msg.modelname;
devices[index].conf.model.val = msg.model;
iter = 0;
getDeviceInfo(index, msg);
} else {
adapter.log.debug('cb && cb(response)');
cb && cb(response);
}
} else if (msg.protocol === 2){
adapter.log.debug('Парсим ответ от трехфазного счетчика');
if ((response[0] === 0 || response[0] === msg.addr) && response[1] === 0){ //Ответ на поиск 3 фазного
adapter.log.debug('Парсим адрес трехфазного счетчика');
const index = getDeviceIndexAtAddr(response[2]);
devices[index] = m.template[msg.protocol];
devices[index].conf.addr.val = response[2];
devices[index].conf.protocol.val = msg.protocol;
devices[index].conf.model.name = msg.modelname;
devices[index].conf.model.val = msg.model;
if (msg.pwd && msg.user){
devices[index].conf.pwd.val = msg.pwd;
devices[index].conf.user.val = msg.user;
msg.pwd = null;
msg.user = 1;
}
iter = 0;
getDeviceInfo(index, msg);
} else if (response[0] === 0 && response[1] !== 0){
adapter.log.debug('Ошибка запроса - ' + m.options.respcode[response[1]]);
_callback(m.options.respcode[response[1]]);
} else {
adapter.log.debug('cb && cb(response)');
cb && cb(response);
}
}
}
function getDeviceInfo(index, msg, cb){
adapter.log.debug('-----------------------------------------------------------------------------------------------------');
msg.cmd = [];
let addr = [devices[index].conf.addr.val];
if (msg.protocol === 1){
const _addr = Buffer.allocUnsafe(4);
_addr.writeUInt32BE(addr, 0);
addr = (Array.prototype.slice.call(_addr, 0));
}
msg.cmd = msg.cmd.concat(addr, m.options.protocol[msg.protocol].readinfo[iter].code, m.options.protocol[msg.protocol].readinfo[iter].cmd);
adapter.log.debug('Получаем информацию из массива (readinfo) - ' + m.options.protocol[msg.protocol].readinfo[iter].desc + '. cmd = ' + JSON.stringify(msg.cmd) + ' / iter=' + iter);
send(msg, (response) => {
adapter.log.debug('Ответ получен, парсим пакет:');
devices = m.options.protocol[msg.protocol].readinfo[iter].func(devices, index, msg, response);
iter++;
if (iter > m.options.protocol[msg.protocol].readinfo.length - 1){
iter = 0;
saveDevices();
_callback();
} else {
getDeviceInfo(index, msg, cb);
}
});
}
function send(msg, cb){
if (mercury) mercury._events.data = undefined;
timeout && clearTimeout(timeout);
timeout = setTimeout(() => {
adapter.log.debug('No response...');
if (mercury) mercury._events.data = undefined;
pollAllowed = true;
_callback && _callback('No response');
cb && cb('');
}, 5000);
if (serial){
adapter.log.debug('send serial ' + serial.path);
parser.once('data', (response) => {
timeout && clearTimeout(timeout);
checkCRC(response, msg, cb);
cb = null;
});
} else {
adapter.log.debug('send tcp');
mercury.once('data', (response) => {
timeout && clearTimeout(timeout);
checkCRC(response, msg, cb);
cb = null;
});
}
const b1 = ((m.crc(msg.cmd) >> 8) & 0xff);
msg.cmd[msg.cmd.length] = (m.crc(msg.cmd) & 0xff);
msg.cmd[msg.cmd.length] = b1;
const buf = Buffer.from(msg.cmd);
adapter.log.debug('Send cmd - [' + m.toHexString(msg.cmd) + ']');
serial ? serial.write(buf) :mercury.write(buf);
}
function main(){
if (!adapter.systemConfig) return;
adapter.subscribeStates('*');
fastPollingTime = adapter.config.fastpollingtime ? adapter.config.fastpollingtime :5000;
slowPollingTime = adapter.config.slowpollingtime ? adapter.config.slowpollingtime :60000;
startTime = new Date().getTime();
endTime = new Date().getTime();
m.on('debug', (txt) => {
adapter.log.debug('* ' + txt);
});
m.on('info', (txt) => {
adapter.log.info('* ' + txt);
});
const dir = path.join(utils.getAbsoluteDefaultDataDir(), adapter.namespace.replace('.', '_'));
dataFile = path.join(dir, dataFile);
adapter.log.debug('adapter.config = ' + JSON.stringify(adapter.config));
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
fs.readFile(dataFile, (err, data) => {
if (!err){
try {
devices = JSON.parse(data);
connect();
} catch (err) {
fs.writeFile(dataFile, '', (err) => {
if (err) adapter.log.error('writeFile ERROR = ' + JSON.stringify(err));
connect();
});
}
} else {
fs.writeFile(dataFile, '', (err) => {
if (err) adapter.log.error('writeFile ERROR = ' + JSON.stringify(err));
connect();
});
}
});
}
function connect(){
if (adapter.config.typeconnect === 'tcp' && adapter.config.ip && adapter.config.tcpport){
connectTCP();
} else if (adapter.config.typeconnect === 'usb' && adapter.config.usbport){
serial = new SerialPort(adapter.config.usbport, {
baudRate: parseInt(adapter.config.baud, 10),
parity: adapter.config.parity ? 'even' :'none', //'none', 'even', 'mark', 'odd', 'space'.
dataBits: 8,
endOnClose: false,
autoOpen: false
});
const interval = parseInt(adapter.config.timeoutresponse, 10) || 500;
parser = serial.pipe(new InterByteTimeout({maxBufferSize: 512, interval: interval})); //
serial.setMaxListeners(10);
parser.setMaxListeners(10);
connectSerial();
}
}
function openSerialPort(){
serial.open((err) => {
if (err){
adapter.log.error('serial open ' + adapter.config.usbport + ' ERROR: ' + err.message);
reconnect();
}
});
}
function connectSerial(){
try {
serial.on('open', () => {
adapter.log.info('Connected to port ' + adapter.config.usbport);
adapter.setState('info.connection', true, true);
pollAllowed = true;
isOnline = true;
if (devices && devices.length > 0) poll();
});
serial.on('readable', () => {
adapter.log.debug('readable Data:', serial.read());
});
serial.on('error', (err) => {
//if(!serial.isOpen){
adapter.log.error('Serial ' + adapter.config.usbport + ' ERROR: ' + err.message);
//}
//reconnect();
});
serial.on('close', (err) => {
if (err){
adapter.log.debug('serial closed: ' + err.message);
}
reconnect();
});
} catch (e) {
adapter.log.error('SerialPort ERROR = ' + JSON.stringify(e));
}
openSerialPort();
}
function connectTCP(){
adapter.log.debug('Connect to ' + adapter.config.ip + ':' + adapter.config.tcpport);
mercury = new net.Socket();
mercury.connect({host: adapter.config.ip, port: adapter.config.tcpport}, () => {
adapter.log.info('Connected to server ' + adapter.config.ip + ':' + adapter.config.tcpport);
adapter.setState('info.connection', true, true);
pollAllowed = true;
isOnline = true;
if (devices && devices.length > 0) poll();
});
mercury.on('close', (e) => {
adapter.log.debug('closed ' + JSON.stringify(e));
//reconnect();
});
mercury.on('error', (e) => {
adapter.log.error('Mercury ERROR: ' + JSON.stringify(e));
/*if (!e.code || e.code === 'EISCONN' || e.code === 'EPIPE' || e.code === 'EALREADY' || e.code === 'EINVAL' || e.code === 'ECONNRESET' || e.code === 'ENOTFOUND' || e.code === 'ECONNREFUSED')*/
reconnect();
});
mercury.on('end', () => {
adapter.log.debug('Disconnected from server');
reconnect();
_callback && _callback('Disconnected from server');
});
}
function reconnect(){
pollAllowed = false;
isOnline = false;
adapter.setState('info.connection', false, true);
adapter.log.debug('Mercury reconnect after 20 seconds');
reconnectTimeOut && clearTimeout(reconnectTimeOut);
poll_index++;
reconnectTimeOut = setTimeout(() => {
if (mercury) mercury._events.data = undefined;
if (serial) serial._events.data = undefined;
serial && serial.close();
serial ? openSerialPort() :connectTCP();
}, 20000);
}
function openChannel(index, msg, cb){
msg.protocol = index ? devices[index].conf.protocol.val :msg.protocol;
if (msg.protocol === 2){
//msg.addr = index ? devices[index].conf.addr.val :msg.addr;
/*if(index !== null){
msg.addr = devices[index].conf.addr.val;
}*/
if (index !== null){
msg.addr = devices[index].conf.addr.val;
msg.pwd = devices[index].conf.pwd.val;
msg.user = parseInt(devices[index].conf.user.val, 10);
}
msg.cmd = [msg.addr, 0x01, msg.user].concat(msg.pwd);
adapter.log.debug('Открываем канал связи msg = ' + JSON.stringify(msg));
send(msg, (response) => {
if (response.length === 4 && response[1] === 0){
adapter.log.debug('Канал связи открыт');
cb();
} else {
//adapter.log.error('Error: opening communication channel');
if (mercury || serial){
reconnect();
} else {
cb && cb('Error: opening communication channel');
}
}
});
} else {
cb && cb();
}
}
const checkCRC = function (response, msg, cb){
adapter.log.debug('RESPONSE = ' + JSON.stringify(response));
const crc_packet = (response.slice(response.length - 2, response.length)).toJSON().data.toString();
const crc_calc = [(m.crc(response.slice(0, response.length - 2)) & 0xff), ((m.crc(response.slice(0, response.length - 2)) >> 8) & 0xff)].toString();
if (crc_packet === crc_calc){
adapter.log.debug('CRC check packet successfully - CRC packet(' + JSON.stringify(crc_packet) + ') = CRC calc(' + JSON.stringify(crc_calc) + ')');
if (cb){
CRCTimeOut = setTimeout(() => {
cb(response);
}, 100);
} else {
parseFindPacket(response, msg, cb);
}
} else {
adapter.log.debug('check CRC error - CRC packet(' + JSON.stringify(crc_packet) + ') != CRC calc(' + JSON.stringify(crc_calc) + ')');
pollAllowed = true;
_callback && _callback('CRC Error');
cb && cb('');
}
};
const getDeviceIndexAtAddr = function (addr){
let index = null;
devices.some((item, i) => {
if (devices[i].conf.addr.val === addr) index = i;
});
if (index !== null){
return index;
} else {
return devices.length;
}
};
const getDeviceIndexAtSn = function (s){
let index = null;
devices.some((item, i) => {
if (devices[i].info.sn.val === s) index = i;
});
if (index !== null){
return index;
} else {
return devices.length;
}
};
function saveDevices(){
adapter.log.debug('Сохраняем в файл');
const data = JSON.stringify(devices, null, 2);
fs.writeFile(dataFile, data, (err) => {
if (err) adapter.log.error('writeFile Error - ' + err);
adapter.log.debug('Данные сохранены в файл успешно.');
});
}
function listSerial(){
return SerialPort.list()
.then(ports =>
ports.map(port => {
return {path: port.path};
})
).catch(err => {
adapter.log.error(err);
return {path: 'Not available'};
});
}
const addrToArray = function (addrInt){
const _addr = Buffer.allocUnsafe(4);
_addr.writeUInt32BE(parseInt(addrInt, 10), 0);
return Array.prototype.slice.call(_addr, 0);
};
function setStates(index, name, desc, val, unit){
if (((val > -5 && val < 0) || val === null) && !~name.indexOf('cosfTotal')){
val = 0;
}
adapter.getObject(name, function (err, obj){
//adapter.log.debug('getState / err = ' + err + ' / name = ' + name + ' / state = ' + JSON.stringify(state));
if (err || !obj){
const role = 'state';
const _unit = unit ? unit :'';
let type = 'number';
if (~name.indexOf('RAW')) type = 'string';
adapter.log.debug('setObject = ' + name + ' { val = ' + val + '}');
adapter.setObject(name, {
type: 'state',
common: {
name: desc,
desc: desc,
type: type,
unit: _unit,
role: role
},
native: {}
});
adapter.setState(name, {val: val, ack: true});
} else {
if (obj.common.desc !== desc || obj.common.unit !== unit){
adapter.extendObject(name, {common: {name: desc, desc: desc, unit: unit}});
}
adapter.getState(name, function (err, state){
if (state){
if (state.val === val){
adapter.log.debug('setState ' + name + ' { oldVal: ' + state.val + ' = newVal: ' + val + ' }');
} else if (state.val !== val){
adapter.setState(name, {val: val, ack: true});
adapter.log.debug('setState ' + name + ' { oldVal: ' + state.val + ' != newVal: ' + val + ' }');
}
}
});
}
});
}
function setDev(index){
adapter.log.debug('------------ setDev -------------');
const prefix = devices[index].info.sn.val.toString();
let img = parseInt(devices[index].conf.model.val);
if (img === 230 || img === 231 || img === 234) img = img + '' + devices[index].info.typeCount.val;
const icon = 'img/' + img + '.png';
adapter.setObjectNotExists(prefix, {
type: 'device',
common: {name: devices[index].conf.name.val, type: 'string', icon: icon},
native: {id: prefix}
}, () => {
adapter.extendObject(prefix, {common: {name: devices[index].conf.name.val, type: 'string', icon: icon}});
setStates(index, prefix + '.RAW', 'Send RAW command to counter', '');
});
}
function setObjects(index){
adapter.log.debug('------------ setObjects -------------');
let name, val;
const obj = devices[index].metering;
let desc = '';
let unit = '';
const prefix = devices[index].info.sn.val;
setDev(index);
for (const key1 in obj) {
if (!Object.hasOwnProperty.call(obj, key1)) continue;
name = prefix + '.' + key1;
//adapter.log.debug('key1 = ' + key1 + ' / name = ' + name);
if (obj[key1]['val'] === undefined){
const obj1 = obj[key1];
for (const key2 in obj1) {
if (!Object.hasOwnProperty.call(obj1, key2)) continue;
name = prefix + '.' + key1 + '.' + key2;
//adapter.log.debug('key2 = ' + key2 + ' / name = ' + name);
if (obj1[key2]['val'] === undefined){
const obj2 = obj1[key2];
for (const key3 in obj2) {
if (!Object.hasOwnProperty.call(obj2, key3)) continue;
name = prefix + '.' + key1 + '.' + key2 + '.' + key3;
//adapter.log.debug('key3 = ' + key3 + ' / name = ' + name);
if (obj2[key3]['val'] === undefined){
const obj3 = obj2[key3];
for (const key4 in obj3) {
if (!Object.hasOwnProperty.call(obj3, key4)) continue;
desc = obj3[key4].desc;
unit = obj3[key4].unit;
val = obj3[key4].val;
name = prefix + '.' + key1 + '.' + key2 + '.' + key3 + '.' + key4;
//adapter.log.debug('key4 = ' + key4 + ' / name = ' + name);
setStates(index, name, desc, val, unit);
}
} else {
desc = obj2[key3].desc;
unit = obj2[key3].unit;
val = obj2[key3].val;
setStates(index, name, desc, val, unit);
}
}
} else {
desc = obj1[key2].desc;
unit = obj1[key2].unit;
val = obj1[key2].val;
setStates(index, name, desc, val, unit);
}
}
} else {
desc = obj[key1].desc;
unit = obj[key1].unit;
val = obj[key1].val;
setStates(index, name, desc, val, unit);
}
}
}
if (module.parent){
module.exports = startAdapter;
} else {
startAdapter();
}