iobroker.ems-esp
Version:
EMS-ESP and KM200 Interface
493 lines (449 loc) • 17.2 kB
JavaScript
/* eslint-disable no-empty */
const Syslog = require('simple-syslog-server');
const fs = require('node:fs');
let server;
let telegrams = [],
syslog = [];
let unloaded = false;
let active = false;
let active_old = false;
let adapter, utils, fn;
const init = async function (a, u) {
adapter = a;
utils = u;
const dataDir = utils.getAbsoluteDefaultDataDir(); // /opt/iobroker/iobroker-data
await fs.promises.mkdir(`${dataDir}/ems-esp/${adapter.instance}`, { recursive: true });
fn = `${dataDir}/ems-esp/${adapter.instance}/syslog`;
adapter = a;
await init_syslog();
try {
await syslog_server();
} catch (err) {
adapter.log.info(err);
}
};
async function syslog_server() {
const options = { type: 'udp4' };
const address = ''; // Any
let port = 0;
let state = await adapter.getStateAsync('syslog.server.port');
if (state != null) {
port = state.val;
}
if (port == 0) {
return;
}
const listen = { host: address, port: port };
server = Syslog.UDP(options);
state = await adapter.getStateAsync('syslog.activated');
if (state != null) {
active = state.val;
}
adapter.setStateAsync('syslog.server.active', { ack: true, val: false });
// Start Syslog Server ---------------------------------------------------------------------------------------------------------------------------------
server
.on('msg', data => {
if (!unloaded) {
sys(data);
} else {
adapter.log.info('syslog server closed due to adapter stop');
server.close();
return;
}
})
.on('error', err => {
adapter.log.error(`syslog error :${err}`);
server.close();
return;
})
.listen(listen)
.then(() => {
adapter.log.info(`syslog server now listening on port:${port}`);
})
.catch(err => {
adapter.log.error(err);
});
}
// Anaylse syslog data stream ------------------------------------------------------------------------------------------------------------------------------
async function sys(data) {
try {
let fsrc = '',
fdest = '',
ftype = '',
fpolling = false,
fvalue = '';
adapter.getState('syslog.activated', function (err, state) {
if (state != null) {
active = state.val;
}
});
const state = await adapter.getStateAsync('syslog.activated');
active = state.val;
if (active_old == false && active == true) {
telegrams = [];
syslog = [];
const time = new Date();
const d = { time: time.toLocaleString(), telegram: 'Start' };
telegrams.unshift(d);
await adapter.setStateAsync('syslog.telegrams', { ack: true, val: JSON.stringify(telegrams) });
await adapter.setStateAsync('syslog.telegram.dest', { ack: true, val: '' });
await adapter.setStateAsync('syslog.telegram.type', { ack: true, val: '' });
await adapter.setStateAsync('syslog.telegram.type_text', { ack: true, val: '' });
await adapter.setStateAsync('syslog.telegram.type_raw', { ack: true, val: '' });
await adapter.setStateAsync('syslog.telegram.data', { ack: true, val: '' });
await adapter.setStateAsync('syslog.telegram.offset', { ack: true, val: '' });
await adapter.setStateAsync('syslog.telegram.telegram_raw', { ack: true, val: '' });
}
if (active_old == true && active == false) {
write_file(fn, telegrams);
}
active_old = active;
adapter.setStateAsync('syslog.server.active', { ack: true, val: true });
adapter.setStateAsync('syslog.server.data', { ack: true, val: JSON.stringify(data) });
s_list(syslog, data);
let state1 = await adapter.getStateAsync('syslog.filter.src');
if (state1 != null) {
fsrc = state1.val;
}
state1 = await adapter.getStateAsync('syslog.filter.dest');
if (state1 != null) {
fdest = state1.val;
}
state1 = await adapter.getStateAsync('syslog.filter.type');
if (state1 != null) {
ftype = state1.val;
}
state1 = await adapter.getStateAsync('syslog.filter.value');
if (state1 != null) {
fvalue = state1.val;
}
state1 = await adapter.getStateAsync('syslog.filter.polling');
if (state1 != null) {
fpolling = state1.val;
}
let p1 = false,
p2 = false,
p3 = false,
p4 = false,
p5 = false,
src = '',
dest = '',
type = '',
typet = '',
typer = '',
offset = '',
tdata = '',
tg = [];
if (data.msg.substr(0, 3) == 'Rx:') {
const pos1 = data.msg.indexOf(':');
if (pos1 > -1) {
data.msg = data.msg.substring(pos1 + 2);
}
tg = data.msg.split(' ');
src = tg[0];
dest = tg[1];
type = tg[2];
typer = type;
offset = tg[3];
tdata = '';
for (let i = 4; i < tg.length - 1; i++) {
if (i == 4) {
tdata = tg[i];
} else {
tdata += ` ${tg[i]}`;
}
}
if (fsrc == src || fsrc == '') {
p1 = true;
}
if (fdest == dest || fdest == '') {
p2 = true;
}
const bits = `00000000${parseInt(dest, 16).toString(2)}`.substr(-8);
const bit8 = bits.substring(0, 1);
p3 = true;
if (bit8 == '1' && fpolling == false) {
p3 = false;
}
if ((type == 'FF' || type == 'F9') && bit8 == '0') {
typer = tg[4] + tg[5];
//if (typer.substr(0,1) == "0") typer = typer.substr(1,3);
let hexValue = parseInt(typer, 16);
hexValue = hexValue + 0x0100;
type = hexValue.toString(16).toUpperCase();
tdata = '';
for (let i = 6; i < tg.length - 1; i++) {
if (i == 6) {
tdata = tg[i];
} else {
tdata += ` ${tg[i]}`;
}
}
}
if ((type == 'FF' || type == 'F9') && bit8 == '1') {
typer = tg[5] + tg[6];
//if (typer.substr(0,1) == "0") typer = typer.substr(1,3);
let hexValue = parseInt(typer, 16);
hexValue = hexValue + 0x0100;
type = hexValue.toString(16).toUpperCase();
tdata = tg[4];
}
if (ftype == type || ftype == '' || ftype == typer) {
p4 = true;
}
p5 = false;
if (fvalue == '') {
p5 = true;
}
if (fvalue != '' && tdata.indexOf(fvalue) >= 0) {
p5 = true;
}
}
const m1 = data.msg.search('->');
const m2 = data.msg.search('<-');
if (m1 > -1 || m2 > -1) {
p3 = true;
if (m2 > -1 && fpolling == false) {
p3 = false;
}
let d = data.msg;
let p11 = d.search(/\(/);
let p12 = d.search(/\)/);
src = d.substring(p11 + 3, p12);
if (fsrc == src || fsrc == '') {
p1 = true;
}
d = d.substring(p12 + 1);
p11 = d.search(/\(/);
p12 = d.search(/\)/);
dest = d.substring(p11 + 3, p12);
if (m2 > -1) {
if (dest == '08') {
dest = '88';
}
if (dest == '10') {
dest = '90';
}
}
if (fdest == dest || fdest == '') {
p2 = true;
}
d = d.substring(p12 + 1);
p11 = d.search(/\(/);
typet = d.substring(2, p11);
p12 = d.search(/\)/);
type = d.substring(p11 + 3, p12);
typer = type;
if (typer.length >= 3) {
let hexValue = parseInt(typer, 16);
hexValue = hexValue - 0x0100;
typer = hexValue.toString(16).toUpperCase();
if (typer.length == 3) {
typer = `0${typer}`;
}
}
if (ftype == type || ftype == '' || ftype == typer || ftype == typet) {
p4 = true;
}
d = d.substring(p12 + 1);
p11 = d.search(/\(/);
p12 = d.search(/\)/);
offset = '00';
if (p11 > -1 && p12 > -1) {
offset = d.substring(p11 + 8, p12);
}
const offn = parseInt(offset);
offset = offn.toString(16);
if (p11 == -1) {
tdata = d.substring(8);
}
if (p11 > -1) {
tdata = d.substring(8, p11);
}
p5 = false;
if (fvalue == '') {
p5 = true;
}
if (fvalue != '' && tdata.indexOf(fvalue) >= 0) {
p5 = true;
}
}
if (p1 && p2 && p3 && p4 && p5 && active && !unloaded) {
await adapter.setStateAsync('syslog.telegram.telegram_raw', { ack: true, val: data.msg });
await adapter.setStateAsync('syslog.telegram.src', { ack: true, val: src });
await adapter.setStateAsync('syslog.telegram.dest', { ack: true, val: dest });
await adapter.setStateAsync('syslog.telegram.type', { ack: true, val: type });
await adapter.setStateAsync('syslog.telegram.type_text', { ack: true, val: typet });
await adapter.setStateAsync('syslog.telegram.type_raw', { ack: true, val: typer });
await adapter.setStateAsync('syslog.telegram.offset', { ack: true, val: offset });
await adapter.setStateAsync('syslog.telegram.data', { ack: true, val: tdata });
if (tdata != '<empty>' && tdata != '') {
t_list(telegrams, data.msg);
}
}
} catch {}
}
function write_file(fn, telegrams) {
const fnw = `${fn}_${Date.now()}.txt`;
let data = '';
for (let i = 0; i < telegrams.length; i++) {
data += `${JSON.stringify(telegrams[i])} \n`;
}
try {
fs.writeFileSync(fnw, data, 'utf8');
} catch (err) {
adapter.log.info(err);
}
}
function t_list(telegrams, t) {
const max = 1000;
const time = new Date();
const d = { time: time.toLocaleString(), telegram: t };
telegrams.unshift(d);
if (telegrams.length > max) {
telegrams.pop();
}
adapter.setStateAsync('syslog.telegrams', { ack: true, val: JSON.stringify(telegrams) });
}
function s_list(syslog, s) {
const max = 1000;
syslog.unshift(s);
if (syslog.length > max) {
syslog.pop();
}
adapter.setStateAsync('syslog.server.syslog', { ack: true, val: JSON.stringify(syslog) });
}
async function init_syslog() {
await adapter.setObjectNotExistsAsync('syslog.filter.src', {
type: 'state',
common: { type: 'string', name: 'syslog source filter', role: 'value', read: true, write: true },
native: {},
});
adapter.getState('syslog.filter.src', function (err, state) {
if (state == null) {
adapter.setStateAsync('syslog.filter.src', { ack: true, val: '' });
}
});
await adapter.setObjectNotExistsAsync('syslog.filter.dest', {
type: 'state',
common: { type: 'string', name: 'syslog destination filter', role: 'value', read: true, write: true },
native: {},
});
adapter.getState('syslog.filter.dest', function (err, state) {
if (state == null) {
adapter.setStateAsync('syslog.filter.dest', { ack: true, val: '' });
}
});
await adapter.setObjectNotExistsAsync('syslog.filter.type', {
type: 'state',
common: { type: 'string', name: 'syslog type filter', role: 'value', read: true, write: true },
native: {},
});
adapter.getState('syslog.filter.type', function (err, state) {
if (state == null) {
adapter.setStateAsync('syslog.filter.type', { ack: true, val: '' });
}
});
await adapter.setObjectNotExistsAsync('syslog.filter.value', {
type: 'state',
common: { type: 'string', name: 'syslog value filter', role: 'value', read: true, write: true },
native: {},
});
adapter.getState('syslog.filter.value', function (err, state) {
if (state == null) {
adapter.setStateAsync('syslog.filter.value', { ack: true, val: '' });
}
});
await adapter.setObjectNotExistsAsync('syslog.filter.polling', {
type: 'state',
common: { type: 'boolean', name: 'syslog polling filter', role: 'value', read: true, write: true },
native: {},
});
adapter.getState('syslog.filter.polling', function (err, state) {
if (state == null) {
adapter.setStateAsync('syslog.filter.polling', { ack: true, val: false });
}
});
await adapter.setObjectNotExistsAsync('syslog.server.active', {
type: 'state',
common: { type: 'boolean', name: 'syslog server active?', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.server.data', {
type: 'state',
common: { type: 'object', name: 'syslog data', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.server.port', {
type: 'state',
common: { type: 'number', name: 'syslog port number', role: 'value', read: true, write: true },
native: {},
});
await adapter.setStateAsync('syslog.server.port', { ack: true, val: adapter.config.syslog_port });
await adapter.setObjectNotExistsAsync('syslog.server.syslog', {
type: 'state',
common: { type: 'json', name: 'syslog json-list', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.src', {
type: 'state',
common: { type: 'string', name: 'telegram source', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.dest', {
type: 'state',
common: { type: 'string', name: 'telegram destination', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.type', {
type: 'state',
common: { type: 'string', name: 'telegram type-id', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.type_text', {
type: 'state',
common: { type: 'string', name: 'telegram type-id text', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.offset', {
type: 'state',
common: { type: 'mixed', name: 'telegram offset', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.data', {
type: 'state',
common: { type: 'string', name: 'telegram data', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.type_raw', {
type: 'state',
common: { type: 'string', name: 'telegram type raw (as in telegram)', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.telegram.telegram_raw', {
type: 'state',
common: { type: 'string', name: 'telegram', role: 'value', read: true, write: true },
native: {},
});
await adapter.setObjectNotExistsAsync('syslog.activated', {
type: 'state',
common: { type: 'boolean', name: 'syslog telegram analysis active?', role: 'value', read: true, write: true },
native: {},
});
adapter.getState('syslog.activated', function (err, state) {
if (state == null) {
adapter.setStateAsync('syslog.activated', { ack: true, val: false });
}
});
await adapter.setObjectNotExistsAsync('syslog.telegrams', {
type: 'state',
common: { type: 'json', name: 'telegrams json-list', role: 'value', read: true, write: true },
native: {},
});
}
const unload = function (u) {
unloaded = u;
adapter.log.info('syslog server closed due to adapter stop');
server.close();
};
module.exports = { init, unload };