iobroker.tinker
Version:
Tinker Board-Monitor for ioBroker Installations
298 lines (266 loc) • 11.6 kB
JavaScript
/**
* Tinker Board-Monitor Adapter
*
* License: MIT
*/
/* jshint -W097 */
/* jshint strict: false */
/*jslint node: true */
;
const utils = require('@iobroker/adapter-core'); // Get common adapter utils
const exec = require('child_process').execSync;
const adapterName = require('./package.json').name.split('.').pop();
let adapter;
let timer;
let config;
let objects;
let tinker = {};
let table = {};
let errorsLogged = {};
function startAdapter(options) {
options = options || {};
Object.assign(options, { name: adapterName });
adapter = new utils.Adapter(options);
adapter.on('ready', () => {
config = adapter.config;
if (adapter.config.forceinit) {
adapter.getObjectList({ startkey: `${adapter.name}.${adapter.instance}`, endkey: `${adapter.name}.${adapter.instance}\u9999` }, function (err, res) {
res = res.rows;
for (let i = 0; i < res.length; i++) {
const id = res[i].doc.common.name;
adapter.log.debug(`Remove ${id}: ${id}`);
adapter.delObject(id, function (res, err) {
if (res !== undefined && res !== 'Not exists') adapter.log.error(`res from delObject: ${res}`);
if (err !== undefined) adapter.log.error(`err from delObject: ${err}`);
});
adapter.deleteState(id, function (res, err) {
if (res !== undefined && res !== 'Not exists') adapter.log.error(`res from deleteState: ${res}`);
if (err !== undefined) adapter.log.error(`err from deleteState: ${err}`);
});
}
});
}
adapter.subscribeStates('*');
adapter.getObjectList({ include_docs: true }, function (err, res) {
res = res.rows;
objects = {};
for (let i = 0; i < res.length; i++) {
objects[res[i].doc._id] = res[i].doc;
}
adapter.log.debug('received all objects');
main(adapter);
});
});
adapter.on('stateChange', (id, state) => {
adapter.log.debug(`stateChange for ${id} found state = ${JSON.stringify(state)}`);
});
adapter.on('unload', (callback) => {
try {
adapter.log.info('cleaned everything up...');
clearInterval(timer);
callback();
} catch (e) {
callback();
}
});
return adapter;
}
function main(adapter) {
// TODO: Check which Objects we provide
timer = setInterval(parser, adapter.config.interval || 60000);
parser();
}
function parser() {
adapter.log.debug('start parsing');
// Workaround, WebStorm
if (config === undefined) {
config = adapter.config;
}
for (let c in config) {
if (!config.hasOwnProperty(c)) continue;
adapter.log.debug(`PARSING: ${c}`);
if (c.indexOf('c_') !== 0 && config[`c_${c}`] === true) {
table[c] = new Array(20);
const o = config[c];
for (let i in o) {
if (!o.hasOwnProperty(i)) continue;
adapter.log.debug(` PARSING: ${i}`);
const object = o[i];
const command = object.command;
let regexp;
if (object.multiline !== undefined) {
regexp = new RegExp(object.regexp, 'm');
} else {
regexp = new RegExp(object.regexp);
}
const post = object.post;
adapter.log.debug(`---> ${command}`);
let stdout;
try {
stdout = exec(command).toString();
adapter.log.debug(`------------- ${stdout}`);
} catch (er) {
adapter.log.debug(er.stack);
if (er.pid) console.log('%s (pid: %d) exited with status %d',
er.file, er.pid, er.status);
// do not process if exec fails
continue;
}
const match = regexp.exec(stdout);
adapter.log.debug(`---> REGEXP: ${regexp}`);
if (match !== undefined && match !== null && match.length !== undefined) {
adapter.log.debug(`GROUPS: ${match.length}`);
}
// TODO: if Group Match is bigger then 2
// split groups and header into seperate objects
if (match !== undefined && match !== null && match.length > 2) {
const lname = i.split(',');
for (let m = 1; m < match.length; m++) {
const value = match[m];
const name = lname[m - 1];
adapter.log.debug(`MATCHING: ${value}`);
adapter.log.debug(`NAME: ${name}, VALULE: ${value}`);
tinker[name] = value;
table[c][i] = value;
}
} else {
adapter.log.debug(`---> POST: ${post}`);
let value;
if (match !== undefined && match !== null) {
value = match[1];
} else {
value = stdout;
}
tinker[i] = value;
table[c][i] = value;
}
}
}
}
// TODO: Parse twice to get post data and evaluate
for (let c in config) {
if (!config.hasOwnProperty(c)) continue;
adapter.log.debug(`CURRENT = ${c} ${config[`c_${c}`]}`);
adapter.log.debug(c.indexOf('c_'));
if (c.indexOf('c_') !== 0 && config[`c_${c}`]) {
if (objects[c] === undefined) {
const stateObj = {
common: {
name: c, // You can add here some description
read: true,
write: true,
role: 'sensor'
},
type: 'device',
_id: c
};
adapter.extendObject(c, stateObj);
}
const o = config[c];
for (let i in o) {
if (!o.hasOwnProperty(i)) continue;
const object = o[i];
const command = object.command;
const post = object.post;
adapter.log.debug(`---> POST: ${post} for ${i} in ${o}`);
let value;
const lname = i.split(',');
if (lname !== undefined && lname.length > 1) {
for (let m = 0; m < lname.length; m++) {
const name = lname[m];
value = tinker[name];
// TODO: Check if value is number and format it 2 Digits
if (!isNaN(value)) {
value = parseFloat(value);
const re = new RegExp(/^\d+\.\d+$/);
if (re.exec(value)) {
value = parseFloat(value.toFixed(2));
}
}
adapter.log.debug(`MATCHING: ${value}`);
adapter.log.debug(`NAME: ${name} VALULE: ${value}`);
const objectName = `${adapter.name}.${adapter.instance}.${c}.${name}`;
adapter.log.debug(`SETSTATE FOR ${objectName} VALUE = ${value}`);
if (objects[objectName] === undefined) {
// TODO Create an Objecttree
const stateObj = {
common: {
name: objectName, // You can add here some description
read: true,
write: true,
state: 'state',
role: 'value',
type: 'number'
},
type: 'state',
_id: objectName
};
adapter.extendObject(objectName, stateObj);
}
adapter.setState(objectName, {
val: value,
ack: true
});
}
} else {
value = tinker[i];
if (value !== undefined && value !== '' && value !== null) {
if (post.indexOf('$1') !== -1) {
adapter.log.debug(`VALUE: ${value} POST: ${post}`);
try {
value = eval(post.replace('$1', value));
} catch (e) {
adapter.log.error(`Cannot evaluate: ${post.replace('$1', value)}`);
value = NaN;
}
}
// TODO: Check if value is number and format it 2 Digits
if (!isNaN(value)) {
value = parseFloat(value);
const r = new RegExp(/^\d+\.\d+$/);
if (r.exec(value)) {
value = parseFloat(value.toFixed(2));
}
}
const objectName = `${adapter.name}.${adapter.instance}.${c}.${i}`;
adapter.log.debug(`SETSTATE FOR ${objectName} VALUE = ${value}`);
if (objects[objectName] === undefined) {
// TODO Create an Objecttree
const stateObj = {
common: {
name: objectName, // You can add here some description
read: true,
write: true,
state: 'state',
role: 'value',
type: 'mixed'
},
type: 'state',
_id: objectName
};
adapter.extendObject(objectName, stateObj);
}
adapter.setState(objectName, {
val: value,
ack: true
});
} else {
if (i === 'wifi_send' || i === 'wifi_received') {
adapter.log.debug(`No Value found for ${i}`);
} else if (!errorsLogged[i]) {
adapter.log.error(`No Value found for ${i}`);
errorsLogged[i] = true;
}
}
}
}
}
}
}
// If started as allInOne/compact mode => return function to create instance
if (module && module.parent) {
module.exports = startAdapter;
} else {
// or start the instance directly
startAdapter();
}