Initial commit - ip 10.0.0.74
This commit is contained in:
commit
e189e5334b
24 changed files with 3518 additions and 0 deletions
6
config
Normal file
6
config
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
name : Total.js Flow
|
||||||
|
|
||||||
|
// Packages settings
|
||||||
|
package#flow (Object) : { url: '/' }
|
||||||
|
|
||||||
|
table.settings: rvo_name:string|lang:string|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number
|
||||||
0
databases/backup/tbdata.nosql
Normal file
0
databases/backup/tbdata.nosql
Normal file
2
databases/settings.table
Normal file
2
databases/settings.table
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
rvo_name:string|lang:string|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number
|
||||||
|
+|Grafia 10.0.0.74|en||10_0_0_74_grafia||1883|0|29|unipi|1|30|50|...........................................
|
||||||
0
databases/tbdata.nosql
Normal file
0
databases/tbdata.nosql
Normal file
90
flow/code.js
Normal file
90
flow/code.js
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
exports.id = 'code';
|
||||||
|
exports.title = 'Code';
|
||||||
|
exports.group = 'Common';
|
||||||
|
exports.color = '#656D78';
|
||||||
|
exports.input = true;
|
||||||
|
exports.output = 1;
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.icon = 'code';
|
||||||
|
exports.version = '1.2.0';
|
||||||
|
exports.options = { outputs: 1, code: 'send(0, value);', keepmessage: true };
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div data-jc="textbox" data-jc-path="outputs" data-jc-config="type:number;validation:value > 0;increment:true;maxlength:3">@(Number of outputs)</div>
|
||||||
|
<div class="help m">@(Minimum is 1)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div data-jc="codemirror" data-jc-path="code" data-jc-config="type:javascript;required:true;height:500;tabs:true;trim:true" class="m">@(Code)</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="keepmessage">@(Keep message instance)</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var code_outputs_count;
|
||||||
|
|
||||||
|
ON('open.code', function(component, options) {
|
||||||
|
code_outputs_count = options.outputs = options.outputs || 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
ON('save.code', function(component, options) {
|
||||||
|
if (code_outputs_count !== options.outputs) {
|
||||||
|
if (flow.version < 511) {
|
||||||
|
component.connections = {};
|
||||||
|
setState(MESSAGES.apply);
|
||||||
|
}
|
||||||
|
component.output = options.outputs || 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>`;
|
||||||
|
|
||||||
|
exports.readme = `# Code
|
||||||
|
|
||||||
|
This component executes custom JavaScript code as it is and it doesn't contain any secure scope.
|
||||||
|
|
||||||
|
\`\`\`javascript
|
||||||
|
// value {Object} contains received data
|
||||||
|
// send(outputIndex, newValue) sends a new value
|
||||||
|
// error(value) sends an error
|
||||||
|
// instance {Object} a current component instance
|
||||||
|
// flowdata {Object} a current flowdata
|
||||||
|
// repository {Object} a current repository of flowdata
|
||||||
|
// Example:
|
||||||
|
|
||||||
|
// send() can be execute multiple times
|
||||||
|
send(0, value);
|
||||||
|
\`\`\``;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
instance.on('data', function(response) {
|
||||||
|
if (fn) {
|
||||||
|
try {
|
||||||
|
fn(response.data, instance, response, instance.options, response.repository, require);
|
||||||
|
} catch (e) {
|
||||||
|
response.data = e;
|
||||||
|
instance.throw(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.reconfigure = function() {
|
||||||
|
try {
|
||||||
|
if (instance.options.code) {
|
||||||
|
instance.status('');
|
||||||
|
var code = 'var send = function(index, value) { if (options.keepmessage) { flowdata.data = value; instance.send2(index, flowdata); } else instance.send2(index, value);}; var error = function(err) { instance.throw(err); }; ' + instance.options.code;
|
||||||
|
fn = new Function('value', 'instance', 'flowdata', 'options', 'repository', 'require', code);
|
||||||
|
} else {
|
||||||
|
instance.status('Not configured', 'red');
|
||||||
|
fn = null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
fn = null;
|
||||||
|
instance.error('Code: ' + e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('options', instance.reconfigure);
|
||||||
|
instance.reconfigure();
|
||||||
|
};
|
||||||
11
flow/comment.js
Normal file
11
flow/comment.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
exports.id = 'comment';
|
||||||
|
exports.title = 'Comment';
|
||||||
|
exports.group = 'Common';
|
||||||
|
exports.color = '#704cff';
|
||||||
|
exports.author = 'Martin Smola';
|
||||||
|
exports.icon = 'comment';
|
||||||
|
exports.traffic = false;
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.readme = '# Comment';
|
||||||
|
|
||||||
|
exports.install = function() {};
|
||||||
100
flow/debug.js
Normal file
100
flow/debug.js
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
exports.id = 'debug';
|
||||||
|
exports.title = 'Debug';
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.color = '#967ADC';
|
||||||
|
exports.click = true;
|
||||||
|
exports.input = true;
|
||||||
|
exports.icon = 'bug';
|
||||||
|
exports.version = '2.0.4';
|
||||||
|
exports.options = { enabled: true, repository: false, type: 'data' };
|
||||||
|
exports.readme = `# Debug
|
||||||
|
|
||||||
|
Prints data to the debug tab.`;
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div data-jc="dropdown" data-jc-path="type" data-jc-config="items:Message data|data,Message repository|repository,Message data + Message repository|both;required:true" class="m">@(Output type)</div>
|
||||||
|
<div data-jc="textbox" data-jc-path="property" data-jc-config="placeholder: @(e.g. address.street)" class="m">@(Path to the property (leave empty to show the whole data object))</div>
|
||||||
|
<div data-jc="textbox" data-jc-path="group" data-jc-config="placeholder: @(e.g. Temperature)" class="m">@(A group name)</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="enabled">@(Enabled)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
instance.on('data', function(response) {
|
||||||
|
if (instance.options.enabled) {
|
||||||
|
|
||||||
|
var opt = instance.options;
|
||||||
|
var rep = response.repository;
|
||||||
|
var val = response.data;
|
||||||
|
var id = response.id;
|
||||||
|
|
||||||
|
switch (instance.options.type){
|
||||||
|
case 'both':
|
||||||
|
var data = {};
|
||||||
|
data.repository = rep;
|
||||||
|
data.data = val instanceof Error ? { error: val.message, stack: val.stack } : val;
|
||||||
|
instance.debug(safeparse(opt.property ? U.get(data, opt.property) : data), undefined, opt.group, id);
|
||||||
|
break;
|
||||||
|
case 'repository':
|
||||||
|
instance.debug(safeparse(opt.property ? U.get(rep, opt.property) : rep), undefined, opt.group, id);
|
||||||
|
break;
|
||||||
|
case 'data':
|
||||||
|
default:
|
||||||
|
if (val instanceof Error)
|
||||||
|
instance.debug({ error: val.message, stack: val.stack }, undefined, opt.group, id);
|
||||||
|
else
|
||||||
|
instance.debug(safeparse(opt.property ? U.get(val, opt.property) : val), undefined, opt.group, id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('click', function() {
|
||||||
|
instance.options.enabled = !instance.options.enabled;
|
||||||
|
instance.custom.status();
|
||||||
|
instance.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('options', function() {
|
||||||
|
instance.custom.status();
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.custom.status = function() {
|
||||||
|
instance.status(instance.options.enabled ? 'Enabled' : 'Disabled');
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.custom.status();
|
||||||
|
|
||||||
|
function safeparse(o) {
|
||||||
|
|
||||||
|
if (o instanceof Buffer)
|
||||||
|
return o;
|
||||||
|
|
||||||
|
if (o === undefined)
|
||||||
|
return 'undefined';
|
||||||
|
|
||||||
|
if (o === null)
|
||||||
|
return 'null';
|
||||||
|
|
||||||
|
var cache = [];
|
||||||
|
var str = JSON.stringify(o, function(key, value) {
|
||||||
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
if (cache.indexOf(value) !== -1) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(JSON.stringify(value));
|
||||||
|
} catch (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache.push(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
cache = null;
|
||||||
|
return JSON.parse(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
953
flow/designer.json
Normal file
953
flow/designer.json
Normal file
|
|
@ -0,0 +1,953 @@
|
||||||
|
{
|
||||||
|
"tabs": [
|
||||||
|
{
|
||||||
|
"id": "1636110831878",
|
||||||
|
"name": "Main",
|
||||||
|
"icon": "fa-object-ungroup",
|
||||||
|
"linker": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Time setter",
|
||||||
|
"linker": "time-setter",
|
||||||
|
"id": "1667235000217",
|
||||||
|
"index": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"id": "1636110851291",
|
||||||
|
"component": "socomec",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "IP - 192.168.1.11 & 12",
|
||||||
|
"x": 53,
|
||||||
|
"y": 145,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1636110855097"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1636110863291"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1636461793375"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1643023439891"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1640097360601"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1669850052514"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#2134B0",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"host": "192.168.1.11",
|
||||||
|
"port": 502
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636110855097",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 376,
|
||||||
|
"y": 32,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636110863291",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 377,
|
||||||
|
"y": 113,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636461560741",
|
||||||
|
"component": "virtualwirein",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "tb-prod01-push",
|
||||||
|
"x": 23,
|
||||||
|
"y": 586,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1694077414274"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "tb-prod01-push",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#303E4D",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"wirename": "tb-prod01-push"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636461793375",
|
||||||
|
"component": "virtualwireout",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "tb-prod01-push",
|
||||||
|
"x": 383,
|
||||||
|
"y": 234,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "tb-prod01-push",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#303E4D",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"wirename": "tb-prod01-push"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636971481195",
|
||||||
|
"component": "monitormemory",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Memory",
|
||||||
|
"x": 37,
|
||||||
|
"y": 945,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641906774515"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "804.16 MB / 987.80 MB",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#F6BB42",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"enabled": true,
|
||||||
|
"interval": 30000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636971491099",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 395,
|
||||||
|
"y": 984,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636972747889",
|
||||||
|
"component": "monitorconsumption",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "CPU",
|
||||||
|
"x": 35,
|
||||||
|
"y": 850,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641906812467"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "3.1% / 57.85 MB",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"monitorfiles": true,
|
||||||
|
"monitorconnections": true,
|
||||||
|
"monitorsize": true,
|
||||||
|
"monitorconsumption": true,
|
||||||
|
"enabled": true,
|
||||||
|
"interval": 30000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1636972771931",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 396,
|
||||||
|
"y": 808,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1640097360601",
|
||||||
|
"component": "httprequest",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "grafia-prod01.worksys.io",
|
||||||
|
"x": 380,
|
||||||
|
"y": 317,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1640097392518"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#5D9CEC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"stringify": "json",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "http://192.168.252.2:8005/total_energy",
|
||||||
|
"type": "json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1640097392518",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 697,
|
||||||
|
"y": 317,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641906699312",
|
||||||
|
"component": "monitordisk",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Disk",
|
||||||
|
"x": 35,
|
||||||
|
"y": 1036,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641906732272"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "5.67 GB / 7.26 GB",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#F6BB42",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"enabled": true,
|
||||||
|
"path": "/",
|
||||||
|
"interval": 30000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641906703877",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 396,
|
||||||
|
"y": 1073,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641906732272",
|
||||||
|
"component": "code",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Code",
|
||||||
|
"x": 196,
|
||||||
|
"y": 1034,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641906703877"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907044563"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#656D78",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"keepmessage": true,
|
||||||
|
"code": "let response = {};\n\nresponse.hdd_total = value.total;\nresponse.hdd_free = value.free;\nresponse.hdd_used = value.used;\n\nsend(0, response);",
|
||||||
|
"outputs": 1,
|
||||||
|
"COMPONENT": "code",
|
||||||
|
"NAME": "Code"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641906774515",
|
||||||
|
"component": "code",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Code",
|
||||||
|
"x": 197,
|
||||||
|
"y": 941,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1636971491099"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907044563"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#656D78",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"keepmessage": true,
|
||||||
|
"code": "let response = {};\n\nresponse.memory_total = value.total;\nresponse.memory_free = value.free;\nresponse.memory_used = value.used;\n\nsend(0, response);",
|
||||||
|
"outputs": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641906812467",
|
||||||
|
"component": "code",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Code",
|
||||||
|
"x": 202,
|
||||||
|
"y": 845,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1636972771931"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907044563"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#656D78",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"keepmessage": true,
|
||||||
|
"code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);",
|
||||||
|
"outputs": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641907044563",
|
||||||
|
"component": "virtualwireout",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "send-to-services",
|
||||||
|
"x": 398,
|
||||||
|
"y": 892,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "send-to-services",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#303E4D",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"wirename": "send-to-services"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641907104812",
|
||||||
|
"component": "virtualwirein",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "send-to-services",
|
||||||
|
"x": 65,
|
||||||
|
"y": 1232,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907121073"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "send-to-services",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#303E4D",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"wirename": "send-to-services"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641907121073",
|
||||||
|
"component": "infosender",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Info sender",
|
||||||
|
"x": 304,
|
||||||
|
"y": 1227,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907134719"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907182409"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#2134B0",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"edge": "undefined"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641907134719",
|
||||||
|
"component": "httprequest",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "http://192.168.252.2:8004/sentmessage",
|
||||||
|
"x": 533,
|
||||||
|
"y": 1191,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1641907188601"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#5D9CEC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"stringify": "json",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "http://192.168.252.2:8004/sentmessage",
|
||||||
|
"type": "json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641907182409",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 536,
|
||||||
|
"y": 1295,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1641907188601",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 906,
|
||||||
|
"y": 1189,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1643023439891",
|
||||||
|
"component": "code",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Code",
|
||||||
|
"x": 569,
|
||||||
|
"y": 176,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1643023495930"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#656D78",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"keepmessage": true,
|
||||||
|
"code": "//if(value.hasOwnProperty('1JMYvnx2RzKEo4aWQ7D93vAL8yZV3m9NBePXbrdj'))\n//{\n\t//send(0, value);\n//}\n//if(value.hasOwnProperty('1559') || value.hasOwnProperty('1558'))\nif(value.hasOwnProperty('1559'))\n{\n\tif(value[\"1559\"][0].values.hasOwnProperty(\"total_energy\"))\n\t\t{\n\t\t\tsend(0, value);\n\t\t}\n\n}\n\nif(value.hasOwnProperty('1558'))\n{\n\tif(value[\"1558\"][0].values.hasOwnProperty(\"total_energy\"))\n\t\t{\n\t\t\tsend(0, value);\n\t\t}\n\n}",
|
||||||
|
"outputs": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1643023495930",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Just 1 module",
|
||||||
|
"x": 719,
|
||||||
|
"y": 169,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1660058310860",
|
||||||
|
"component": "virtualwireout",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "send-to-services",
|
||||||
|
"x": 590.5,
|
||||||
|
"y": 633.4166870117188,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "send-to-services",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#303E4D",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"wirename": "send-to-services"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1667235009598",
|
||||||
|
"component": "timesetter",
|
||||||
|
"tab": "1667235000217",
|
||||||
|
"name": "Timesetter",
|
||||||
|
"x": 245.0833282470703,
|
||||||
|
"y": 166,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1667235037440"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#656D78",
|
||||||
|
"notes": "",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1667235012156",
|
||||||
|
"component": "timer",
|
||||||
|
"tab": "1667235000217",
|
||||||
|
"name": "Timer",
|
||||||
|
"x": 38.08332824707031,
|
||||||
|
"y": 249,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1667235009598"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#F6BB42",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"interval": 86400000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1667235031667",
|
||||||
|
"component": "trigger",
|
||||||
|
"tab": "1667235000217",
|
||||||
|
"name": "Trigger",
|
||||||
|
"x": 41.08332824707031,
|
||||||
|
"y": 168,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1667235009598"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#F6BB42",
|
||||||
|
"notes": "",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1667235037440",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1667235000217",
|
||||||
|
"name": "Debug",
|
||||||
|
"x": 441.0833282470703,
|
||||||
|
"y": 162,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1669850052514",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "Http req data",
|
||||||
|
"x": 372.0833282470703,
|
||||||
|
"y": 422,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1694077414274",
|
||||||
|
"component": "httprequest",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "grafia-prod01.worksys.io/rerouting74",
|
||||||
|
"x": 224,
|
||||||
|
"y": 584,
|
||||||
|
"connections": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"index": "0",
|
||||||
|
"id": "1694077451207"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#5D9CEC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "json",
|
||||||
|
"url": "http://192.168.252.2:8005/rerouting74",
|
||||||
|
"method": "POST",
|
||||||
|
"stringify": "json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1694077451207",
|
||||||
|
"component": "debug",
|
||||||
|
"tab": "1636110831878",
|
||||||
|
"name": "rerouting",
|
||||||
|
"x": 591.0833282470703,
|
||||||
|
"y": 529,
|
||||||
|
"connections": {},
|
||||||
|
"disabledio": {
|
||||||
|
"input": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"output": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "Enabled",
|
||||||
|
"color": "gray"
|
||||||
|
},
|
||||||
|
"color": "#967ADC",
|
||||||
|
"notes": "",
|
||||||
|
"options": {
|
||||||
|
"type": "data",
|
||||||
|
"repository": false,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 624
|
||||||
|
}
|
||||||
455
flow/energomonitor_socomec.js
Normal file
455
flow/energomonitor_socomec.js
Normal file
|
|
@ -0,0 +1,455 @@
|
||||||
|
exports.id = 'socomec';
|
||||||
|
exports.title = 'Energomonitor socomec';
|
||||||
|
exports.version = '1.0.3';
|
||||||
|
exports.group = 'Worksys';
|
||||||
|
exports.color = '#2134B0';
|
||||||
|
exports.output = ["red", "white", "yellow"];
|
||||||
|
exports.click = false;
|
||||||
|
exports.author = 'Rastislav Kovac';
|
||||||
|
exports.icon = 'bolt';
|
||||||
|
exports.readme = `Modbus requests to energomonitor socomec suitcase`;
|
||||||
|
|
||||||
|
const streamBuilder = require("./helper/energo_streambuilder");
|
||||||
|
|
||||||
|
const structure = {
|
||||||
|
"192.168.1.11": {
|
||||||
|
51: "i-35", // nový merák I-35, bez zóny
|
||||||
|
16: "i-35", // zmena adresy z 1 na 16 - 13.5.2022
|
||||||
|
"6A": "i-60A",
|
||||||
|
"6B": "i-60B",
|
||||||
|
"7A": "i-60A",
|
||||||
|
"7B": "i-60B",
|
||||||
|
"8A": "i-60A",
|
||||||
|
"8B": "i-60B",
|
||||||
|
9: "i-30",
|
||||||
|
"10A": "i-60A",
|
||||||
|
"10B": "i-60B",
|
||||||
|
"11A": "i-60A",
|
||||||
|
"11B": "i-60B",
|
||||||
|
"12A": "i-60A",
|
||||||
|
"12B": "i-60B",
|
||||||
|
"13A": "i-60A",
|
||||||
|
"13B": "i-60B",
|
||||||
|
"14A": "i-60A",
|
||||||
|
"14B": "i-60B",
|
||||||
|
"15A": "i-60A",
|
||||||
|
"15B": "i-60B",
|
||||||
|
5: "i-30",
|
||||||
|
"2A": "i-60A",
|
||||||
|
"2B": "i-60B",
|
||||||
|
"3A": "i-60A",
|
||||||
|
"3B": "i-60B",
|
||||||
|
"4A": "i-60A",
|
||||||
|
"4B": "i-60B",
|
||||||
|
//novo nainstalovane 28.10.2024
|
||||||
|
"21A": "i-60A",
|
||||||
|
"21B": "i-60B"
|
||||||
|
|
||||||
|
// "36B": "i-60B" // vymyslene kvoli chybe
|
||||||
|
},
|
||||||
|
"192.168.1.12": {
|
||||||
|
18: "i-35",
|
||||||
|
"2A": "i-60A",
|
||||||
|
"2B": "i-60B",
|
||||||
|
"3A": "i-60A",
|
||||||
|
"3B": "i-60B",
|
||||||
|
"4A": "i-60A",
|
||||||
|
"4B": "i-60B",
|
||||||
|
"5A": "i-60A",
|
||||||
|
"5B": "i-60B",
|
||||||
|
"6A": "i-60A",
|
||||||
|
"6B": "i-60B",
|
||||||
|
"7A": "i-60A",
|
||||||
|
"7B": "i-60B",
|
||||||
|
"8A": "i-60A",
|
||||||
|
"8B": "i-60B",
|
||||||
|
"9A": "i-60A",
|
||||||
|
"9B": "i-60B",
|
||||||
|
"10A": "i-60A",
|
||||||
|
"10B": "i-60B",
|
||||||
|
"11A": "i-60A",
|
||||||
|
"11B": "i-60B",
|
||||||
|
"12A": "i-60A",
|
||||||
|
"12B": "i-60B",
|
||||||
|
"13A": "i-60A",
|
||||||
|
"13B": "i-60B",
|
||||||
|
"14A": "i-60A",
|
||||||
|
"14B": "i-60B",
|
||||||
|
"15A": "i-60A",
|
||||||
|
"15B": "i-60B",
|
||||||
|
"16A": "i-60A",
|
||||||
|
"16B": "i-60B",
|
||||||
|
"17A": "i-60A",
|
||||||
|
"17B": "i-60B"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
const modbus = require('jsmodbus');
|
||||||
|
const net = require('net');
|
||||||
|
|
||||||
|
require('events').EventEmitter.defaultMaxListeners = 20;
|
||||||
|
|
||||||
|
|
||||||
|
const allModulesEnergy = {unipi_74: ""}; // key to identify source data
|
||||||
|
const date = new Date();
|
||||||
|
let hour = date.getHours();
|
||||||
|
|
||||||
|
let sendAllModulesEnergy = setInterval(() => {
|
||||||
|
const d = new Date();
|
||||||
|
const h = d.getHours();
|
||||||
|
if(h != hour)
|
||||||
|
{
|
||||||
|
instance.send(2, allModulesEnergy);
|
||||||
|
hour = h;
|
||||||
|
}
|
||||||
|
}, 180000);
|
||||||
|
|
||||||
|
|
||||||
|
instance.on('close', function(){
|
||||||
|
clearInterval(sendAllModulesEnergy);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const conversionTable = streamBuilder.makeStreamsTable(structure);
|
||||||
|
|
||||||
|
// const conversionTable =
|
||||||
|
// {
|
||||||
|
// "192.168.1.11": {
|
||||||
|
// "streams": [
|
||||||
|
// {
|
||||||
|
// "unitId": 1,
|
||||||
|
// "section": "",
|
||||||
|
// "name": 18488,
|
||||||
|
// "tb_value":"phase_1_power",
|
||||||
|
// "bytes": 2,
|
||||||
|
// "multiplier":1,
|
||||||
|
// },
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
const tbNames = {
|
||||||
|
"192.168.1.11": {
|
||||||
|
"51": "1JMYvnx2RzKEo4aWQ7D93vAL8yZV3m9NBePXbrdj", // nový merák I-35, bez zóny
|
||||||
|
"16": "6lQGaY9RDywdVzObj0PZer7Pg4NBn3exEK51LWZq", // zmena adresy z 1 na 16, 13.5.2022
|
||||||
|
"6A": "JzwxZXOvDj1bVrN4nkWeR8A8qdyBl3MRKLpGPgaQ",
|
||||||
|
"6B": "g9OxBZ5KRwNznlY6pApbGmkWXvjdEL4eGQobMDy2",
|
||||||
|
"7A": "OzNMgZ9n43qPbjXmy7zOgGA2DKdYvW5e6pxGRrVa",
|
||||||
|
"7B": "JX1ObgmqGZ54DMyYL7aJzJAEVdve38WKRzwjNrQ9",
|
||||||
|
"8A": "RvmwNz8QPblKp41GD7l4WK7JrLVYoBO92dMegn6W",
|
||||||
|
"8B": "RO8rjaBDy21qPQJzW7oKpD7pK3xmNleVZg9Ed4Gw",
|
||||||
|
"9": "3JjOWdylwgNLzxVab7NPjw0Z2vG64rq8PEB5QmDo",
|
||||||
|
"10A": "Z5KyJe9nEg1QNbWlX0wmnM7oDjBLdqzR83VGv624",
|
||||||
|
"10B": "1JMYvnx2RzKEo4aWQ7D9xzAL8yZV3m9NBePXbrdj",
|
||||||
|
"11A": "PjLblDgRBO6WQqnxmkJwga7Jv3ewZN4p5a89yKdY",
|
||||||
|
"11B": "dz4ojlpP85JMgDLZWkQ12jkaKYqQexEr62GXRV1y",
|
||||||
|
"12A": "d5xjWYMwEJon6rLlK7yl3wkqgV4DaOeNB9ZX3Gzb",
|
||||||
|
"12B": "gRoJEyXVx4qD9er287LwbOkwBzGldaPjLWQKm3Mv",
|
||||||
|
"13A": "K94XLav1glVRnyQ6r01V3Wkme3YJwBxM5oOzdP2j",
|
||||||
|
"13B": "d9x2V5LGYBzXp4mMRAOPr10PloaqJwnQj6DgrNe3",
|
||||||
|
"14A": "B5EoxeMVp4zwr8nqW0Gen57RjvD1PNamOGbLg63Z",
|
||||||
|
"14B": "aw4eELG2DlPMdn1JW0Bz4Z0qQXOZRN3xB5yp8VKr",
|
||||||
|
"15A": "ZmRwd93QL4gaezxEbAx1Xw01prn2XjlPvGyqJ6BO",
|
||||||
|
"15B": "eod9aRWLVl34Gx1Dn7VYmDk2rz6qjgmpEXwQJN5Z",
|
||||||
|
"5": "3a5oqJN1bgnx4Ol9dk8BdqAByE6jQ8mKDWMpGrLV",
|
||||||
|
"2A": "EjgWGnXaLy9opPOz20ngWQk86BlYM3w1deVQvbKr",
|
||||||
|
"2B": "wvKJdZML6mXP4DzWBAXOK87jxNloa5g23Ve9Y1ry",
|
||||||
|
"3A": "Nzp2OoJlqn6r1ZgvdA3RqE7abBwP5G4eE3RQmyxD",
|
||||||
|
"3B": "PLBJzmK1r3Gynd6OW0g2WzAe5wV4vx9bDEqNgYR8",
|
||||||
|
"4A": "52dD6ZlV1QaOpRBmbAqvWb0KnGzWMLj4eJq38Pgo",
|
||||||
|
"4B": "rDbQ84xzwgdqEoPm3kbPWWA9anOZY1RXyBv2LVM6",
|
||||||
|
"21A": "1558",
|
||||||
|
"21B": "1559"
|
||||||
|
// "36B": "vymyslene kvoli chybe"
|
||||||
|
},
|
||||||
|
"192.168.1.12": {
|
||||||
|
"18": "m6EYyZoJ4gWexdjVPARapL7RDOq9wv2N5XzKGplr",
|
||||||
|
"2A": "E6Kg9oDnLWyzPRMva7vW8yAJxp4VG58qO2w1lZYe",
|
||||||
|
"2B": "roKgWqY95V3mXMRzyAjrW6AbLjexpJPvaGDBw826",
|
||||||
|
"3A": "nJL5lPMwBx23YpqRe0rqa4AdamXvWVbOrD4gNzy8",
|
||||||
|
"3B": "XMBbew5z4ELrZa2mRAdZW9k8vPN6gy3DdVYlpKjq",
|
||||||
|
"4A": "gYbDLqlyZVoRerQpB72GgvAWJnwM5z24POKa8Exj",
|
||||||
|
"4B": "zdQO8GwxDqjRgP4137Y5eo7NyKlpem2nL65rvVJY",
|
||||||
|
"5A": "5dBNwRp9graYJxZn409R28klVov1b2QLPDqGm6XK",
|
||||||
|
"5B": "JzwxZXOvDj1bVrN4nkWeZ8A8qdyBl3MRKLpGPgaQ",
|
||||||
|
"6A": "zrR51V2ajQ9ZLygPKkEPVW0YDq38xOJolENBXGnv",
|
||||||
|
"6B": "g9OxBZ5KRwNznlY6pApbymkWXvjdEL4eGQobMDy2",
|
||||||
|
"7A": "OzNMgZ9n43qPbjXmy7zOyGA2DKdYvW5e6pxGRrVa",
|
||||||
|
"7B": "JX1ObgmqGZ54DMyYL7aJZJAEVdve38WKRzwjNrQ9",
|
||||||
|
"8A": "RvmwNz8QPblKp41GD7l4yK7JrLVYoBO92dMegn6W",
|
||||||
|
"8B": "RO8rjaBDy21qPQJzW7oKyD7pK3xmNleVZg9Ed4Gw",
|
||||||
|
"9A": "3JjOWdylwgNLzxVab7NPxw0Z2vG64rq8PEB5QmDo",
|
||||||
|
"9B": "Z5KyJe9nEg1QNbWlX0wmyM7oDjBLdqzR83VGv624",
|
||||||
|
"10A": "1JMYvnx2RzKEo4aWQ7D9MzAL8yZV3m9NBePXbrdj",
|
||||||
|
"10B": "PjLblDgRBO6WQqnxmkJwea7Jv3ewZN4p5a89yKdY",
|
||||||
|
"11A": "WlVJBygjDZMeKX3vnAMWvLk8NqdmG2x1Y69LQ4P5",
|
||||||
|
"11B": "dz4ojlpP85JMgDLZWkQ1njkaKYqQexEr62GXRV1y",
|
||||||
|
"12A": "BaY3Xpy1EbKGjLq2O7m9W27rx8owgQz9P4dDJRmN",
|
||||||
|
"12B": "DbQY6zyveZRwK5drV0Zl4j7joE4XJM83N9xl2nWq",
|
||||||
|
"13A": "apKVJBwOyrP35m2lv7KEqd0YXbeWNd64En9GxRqg",
|
||||||
|
"13B": "o9vbeQlLMVg8j5dq4kedWy0NxZpEmnXzwYKO1ar2",
|
||||||
|
"14A": "gP1eOZVj3Q9lv5aDEk4MbP7rdpqW8yLm2BbKzJxM",
|
||||||
|
"14B": "2O14VBzl8aDmWdNw3A53vOkGyZ5qLJoEMpj6R9ng",
|
||||||
|
"15A": "pE5X8NQPaow6vlOZxk6Yjw0q42ezGBMyWgDVjR3L",
|
||||||
|
"15B": "d5xjWYMwEJon6rLlK7ylywkqgV4DaOeNB9ZX3Gzb",
|
||||||
|
"16A": "6lQGaY9RDywdVzObj0PZdr7Pg4NBn3exEK51LWZq",
|
||||||
|
"16B": "m6EYyZoJ4gWexdjVPARaYL7RDOq9wv2N5XzKGplr",
|
||||||
|
"17A": "gRoJEyXVx4qD9er287LwBOkwBzGldaPjLWQKm3Mv",
|
||||||
|
"17B": "K94XLav1glVRnyQ6r01VpWkme3YJwBxM5oOzdP2j"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const meter51 = ["total_energy","phase_1_power","phase_2_power","phase_3_power","phase_1_voltage","phase_2_voltage",
|
||||||
|
"phase_3_voltage","phase_1_react_power","phase_2_react_power","phase_3_react_power","phase_1_apparent_power",
|
||||||
|
"phase_2_apparent_power","phase_3_apparent_power","total_active_power","total_reactive_power","total_apparent_power"];
|
||||||
|
|
||||||
|
|
||||||
|
class SocketWithClients {
|
||||||
|
|
||||||
|
constructor (ip, data) {
|
||||||
|
|
||||||
|
this.ip = ip;
|
||||||
|
this.data = data;
|
||||||
|
this.options = {
|
||||||
|
'host': this.ip,
|
||||||
|
'port': '502'
|
||||||
|
}
|
||||||
|
this.streams = data.streams; //pole
|
||||||
|
|
||||||
|
this.startSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
startSocket = () => {
|
||||||
|
|
||||||
|
let obj = this;
|
||||||
|
this.index = 0;
|
||||||
|
this.clients = {};
|
||||||
|
this.socket = new net.Socket();
|
||||||
|
|
||||||
|
this.socket.connect(this.options, function() {
|
||||||
|
console.log('Connected to socket server');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('error', function(e) {
|
||||||
|
console.log('socket connection error', e);
|
||||||
|
if(e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') {
|
||||||
|
console.log(exports.title + ' Waiting 1 minute before trying to connect again');
|
||||||
|
setTimeout(obj.startSocket, 60000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('close', function() {
|
||||||
|
console.log('Socket connection closed ' + exports.title + ' Waiting 1 minute before trying to connect again');
|
||||||
|
setTimeout(obj.startSocket, 60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// we create client for all modules (unitIds) and push them into dictionary
|
||||||
|
for( let i = 0; i < obj.data.streams.length; i++)
|
||||||
|
{
|
||||||
|
if(!this.clients.hasOwnProperty(obj.data.streams[i].unitId))
|
||||||
|
{
|
||||||
|
this.clients[obj.data.streams[i].unitId] = new modbus.client.TCP(this.socket, obj.data.streams[i].unitId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket.on('connect', function () {
|
||||||
|
console.log("socket connected");
|
||||||
|
setTimeout(obj.readRegisters, 10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
readRegisters = () => {
|
||||||
|
|
||||||
|
const lenghtOfStreams = this.streams.length;
|
||||||
|
|
||||||
|
if(this.index >= lenghtOfStreams)
|
||||||
|
{
|
||||||
|
this.index = 0;
|
||||||
|
setTimeout(this.readRegisters, 300000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let unitId = this.streams[this.index].unitId;
|
||||||
|
let section = this.streams[this.index].section;
|
||||||
|
|
||||||
|
let register = this.streams[this.index].name;
|
||||||
|
let bytes = this.streams[this.index].bytes;
|
||||||
|
let date = Date.now();
|
||||||
|
let tbval = this.streams[this.index].tb_value;
|
||||||
|
|
||||||
|
// console.log("citam tieto hodnoty",unitId, register, tbval);
|
||||||
|
let obj = this;
|
||||||
|
|
||||||
|
this.clients[unitId].readHoldingRegisters(register, bytes)
|
||||||
|
.then( function (resp) {
|
||||||
|
|
||||||
|
resp = resp.response._body.valuesAsArray;
|
||||||
|
// console.log(unitId, register, tbval, resp);
|
||||||
|
obj.sendData(resp, register, date, unitId, section);
|
||||||
|
|
||||||
|
obj.index++;
|
||||||
|
setTimeout(obj.readRegisters, 0);
|
||||||
|
|
||||||
|
}).catch (function () {
|
||||||
|
|
||||||
|
console.log("error pri citani z grafie", register, unitId, section, tbNames[obj.ip][unitId + section], tbval);
|
||||||
|
|
||||||
|
//! IMPLEMENTOVAT POSIELANIE CHYB PODLA POSLEDNHO REGISTRA V MODULE === "total_power_factor"
|
||||||
|
if(tbval === "total_power_factor")
|
||||||
|
{
|
||||||
|
obj.sendNokStatus(tbNames[obj.ip][unitId + section], date);
|
||||||
|
if(arguments["0"].err == "Offline")
|
||||||
|
{
|
||||||
|
obj.socket.emit("close");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! POSIELANIE NOK STATUSU - posle sa az pri poslednom registri z daneho unitu, nie pri kazdej chybnej hlaske
|
||||||
|
// if(obj.index + 1 == lenghtOfStreams)
|
||||||
|
// {
|
||||||
|
// obj.sendNokStatus(tbNames[obj.ip][unitId + section], date);
|
||||||
|
// }
|
||||||
|
// else if(obj.streams[obj.index + 1].unitId != unitId || obj.streams[obj.index + 1].section != section)
|
||||||
|
// {
|
||||||
|
// obj.sendNokStatus(tbNames[obj.ip][unitId + section], date);
|
||||||
|
// }
|
||||||
|
|
||||||
|
//console.error(require('util').inspect(arguments, {
|
||||||
|
// depth: null
|
||||||
|
//}))
|
||||||
|
|
||||||
|
obj.index++;
|
||||||
|
setTimeout(obj.readRegisters, 0);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
sendNokStatus = (tbName, date) => {
|
||||||
|
|
||||||
|
let dataToTB = {
|
||||||
|
[tbName]: [
|
||||||
|
{
|
||||||
|
"ts": date,
|
||||||
|
"values": {
|
||||||
|
"status": "NOK",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.send(1, dataToTB);
|
||||||
|
// console.log("poslane do tb po chybe", dataToTB[tbName][0], dataToTB);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
sendData = (response, register, date, unitId, section) => {
|
||||||
|
|
||||||
|
let l = this.streams.length;
|
||||||
|
|
||||||
|
for (let i=0; i<l; i++) {
|
||||||
|
|
||||||
|
let a = this.streams[i];
|
||||||
|
if (a.name === register && a.unitId === unitId && a.section === section)
|
||||||
|
{
|
||||||
|
let tb_value = a.tb_value;
|
||||||
|
let value;
|
||||||
|
let l = response.length;
|
||||||
|
let temp_val = 0;
|
||||||
|
|
||||||
|
if (l === 2)
|
||||||
|
{
|
||||||
|
temp_val = (response[0]*(2**16) + response[1]);
|
||||||
|
|
||||||
|
if(temp_val >= (2**31)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (temp_val & 0x80000000), ak vieš robiť logický súčin
|
||||||
|
{
|
||||||
|
//temp_val = temp_val - 2**31; // odstránim MSB bit, eventuálne sa dá použiť aj (temp_val & 0x7FFFFFFF), ak vieš robiť logický súčin
|
||||||
|
//temp_val = temp_val * (-1); // spravím z toho zápornú hodnotu
|
||||||
|
temp_val = temp_val - "0xFFFFFFFF" + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (l === 1)
|
||||||
|
{
|
||||||
|
temp_val = response[0];
|
||||||
|
|
||||||
|
if(temp_val >= (2**15)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (temp_val & 0x8000), ak vieš robiť logický súčin
|
||||||
|
{
|
||||||
|
// temp_val = temp_val - 2**15; // odstránim MSB bit, eventuálne sa dá použiť aj (temp_val & 0x7FFF), ak vieš robiť logický súčin
|
||||||
|
// temp_val = temp_val * (-1); // spravím z toho zápornú hodnotu
|
||||||
|
temp_val = temp_val - "0xFFFF" + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = temp_val;
|
||||||
|
value = value / a.multiplier;
|
||||||
|
|
||||||
|
let tbName = tbNames[this.ip][unitId.toString() + section];
|
||||||
|
// console.log(unitId, register, tbName, tb_value, response, a.multiplier, value, section);
|
||||||
|
// console.log(unitId, register, tb_value, value);
|
||||||
|
|
||||||
|
if(tbName == undefined) return;
|
||||||
|
|
||||||
|
// we handle multimeter 51 values: - if voltage or power, we multiply with 55
|
||||||
|
if(tbName == '1JMYvnx2RzKEo4aWQ7D93vAL8yZV3m9NBePXbrdj' && meter51.includes(tb_value)) value = parseFloat((value * 55).toFixed(2));
|
||||||
|
|
||||||
|
const values = {
|
||||||
|
"status": "OK",
|
||||||
|
[tb_value]: value
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// we send "energy_last_month" value, that is equal to "total_energy" value, on first day and first minute of new month ==> it means when month has changed
|
||||||
|
if(tb_value == "total_energy")
|
||||||
|
{
|
||||||
|
const previousEnergy = a.previousEnergy;
|
||||||
|
a.previousEnergy = value;
|
||||||
|
|
||||||
|
if(previousEnergy != null)
|
||||||
|
{
|
||||||
|
values["energy_update"] = value - previousEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
const d = new Date(date);
|
||||||
|
const currentMonth = d.getMonth();
|
||||||
|
const month = a.month;
|
||||||
|
|
||||||
|
if(month != currentMonth)
|
||||||
|
{
|
||||||
|
values["energy_last_month"] = value;
|
||||||
|
a.month = currentMonth;
|
||||||
|
}
|
||||||
|
|
||||||
|
allModulesEnergy[this.ip + '@' + unitId + section] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let dataToTB = {
|
||||||
|
[tbName]: [
|
||||||
|
{
|
||||||
|
"ts": date,
|
||||||
|
"values": values
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.send(1, dataToTB);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const newSocket = new SocketWithClients("192.168.1.11", conversionTable["192.168.1.11"]);
|
||||||
|
const newSocket2 = new SocketWithClients("192.168.1.12", conversionTable["192.168.1.12"]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
44
flow/helper/db_helper.js
Normal file
44
flow/helper/db_helper.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
function promisifyBuilder(builder)
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
builder.callback(function(err, response) {
|
||||||
|
|
||||||
|
if(err != null) reject(err);
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeMapFromDbResult(response, ...keys)
|
||||||
|
{
|
||||||
|
let s = "-";
|
||||||
|
let data = {};
|
||||||
|
|
||||||
|
for(let i = 0; i < response.length; i++)
|
||||||
|
{
|
||||||
|
let record = response[i];
|
||||||
|
|
||||||
|
let k = [];
|
||||||
|
for(let j = 0; j < keys.length; j++)
|
||||||
|
{
|
||||||
|
k.push( record[keys[j]] );
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = k.join(s);
|
||||||
|
data[ key ] = record;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
promisifyBuilder,
|
||||||
|
makeMapFromDbResult
|
||||||
|
}
|
||||||
207
flow/helper/energo_streambuilder.js
Normal file
207
flow/helper/energo_streambuilder.js
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
// const structure = {
|
||||||
|
// "192.168.1.11": {
|
||||||
|
// 1: "i-35",
|
||||||
|
// "6A": "i-60A",
|
||||||
|
// "6B": "i-60B",
|
||||||
|
// 7: "i-60B"
|
||||||
|
// },
|
||||||
|
// "192.168.1.12": {
|
||||||
|
// 18: "i-35"
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} structure - main keys are IPs of installed modules.
|
||||||
|
* @param {object} structure.ip - configuration of installed modules
|
||||||
|
*/
|
||||||
|
const makeStreamsTable = (structure) => {
|
||||||
|
|
||||||
|
const moduleConfigStructure = {
|
||||||
|
"i-35": {
|
||||||
|
18488: "phase_1_power",
|
||||||
|
18490: "phase_2_power",
|
||||||
|
18492: "phase_3_power",
|
||||||
|
19843: "total_energy",
|
||||||
|
18444: "phase_1_voltage",
|
||||||
|
18446: "phase_2_voltage",
|
||||||
|
18448: "phase_3_voltage",
|
||||||
|
18458: "phase_1_current",
|
||||||
|
18460: "phase_2_current",
|
||||||
|
18462: "phase_3_current",
|
||||||
|
18464: "neutral_wire_current",
|
||||||
|
18494: "phase_1_react_power",
|
||||||
|
18496: "phase_2_react_power",
|
||||||
|
18498: "phase_3_react_power",
|
||||||
|
18512: "phase_1_apparent_power",
|
||||||
|
18514: "phase_2_apparent_power",
|
||||||
|
18516: "phase_3_apparent_power",
|
||||||
|
18518: "phase_1_pf",
|
||||||
|
18519: "phase_2_pf",
|
||||||
|
18520: "phase_3_pf",
|
||||||
|
18476: "total_active_power",
|
||||||
|
18478: "total_reactive_power",
|
||||||
|
18484: "total_apparent_power",
|
||||||
|
18486: "total_power_factor",
|
||||||
|
},
|
||||||
|
"i-30": {
|
||||||
|
19841: "total_energy",
|
||||||
|
18444: "phase_1_voltage",
|
||||||
|
18446: "phase_2_voltage",
|
||||||
|
18448: "phase_3_voltage",
|
||||||
|
18458: "phase_1_current",
|
||||||
|
18460: "phase_2_current",
|
||||||
|
18462: "phase_3_current",
|
||||||
|
18464: "neutral_wire_current",
|
||||||
|
18476: "total_active_power",
|
||||||
|
18478: "total_reactive_power",
|
||||||
|
18484: "total_apparent_power",
|
||||||
|
18486: "total_power_factor",
|
||||||
|
},
|
||||||
|
"i-60A": {
|
||||||
|
19841: "total_energy",
|
||||||
|
18444: "phase_1_voltage",
|
||||||
|
18446: "phase_2_voltage",
|
||||||
|
18448: "phase_3_voltage",
|
||||||
|
18458: "phase_1_current",
|
||||||
|
18460: "phase_2_current",
|
||||||
|
18462: "phase_3_current",
|
||||||
|
18464: "neutral_wire_current",
|
||||||
|
18476: "total_active_power",
|
||||||
|
18478: "total_reactive_power",
|
||||||
|
18484: "total_apparent_power",
|
||||||
|
18486: "total_power_factor",
|
||||||
|
},
|
||||||
|
"i-60B": {
|
||||||
|
21889: "total_energy",
|
||||||
|
20492: "phase_1_voltage",
|
||||||
|
20494: "phase_2_voltage",
|
||||||
|
20496: "phase_3_voltage",
|
||||||
|
20506: "phase_1_current",
|
||||||
|
20508: "phase_2_current",
|
||||||
|
20510: "phase_3_current",
|
||||||
|
20512: "neutral_wire_current",
|
||||||
|
20524: "total_active_power",
|
||||||
|
20526: "total_reactive_power",
|
||||||
|
20532: "total_apparent_power",
|
||||||
|
20534: "total_power_factor",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const bytes = {
|
||||||
|
"phase_1_power": 2,
|
||||||
|
"phase_2_power": 2,
|
||||||
|
"phase_3_power": 2,
|
||||||
|
"total_energy": 2,
|
||||||
|
"phase_1_voltage": 2,
|
||||||
|
"phase_2_voltage": 2,
|
||||||
|
"phase_3_voltage": 2,
|
||||||
|
"phase_1_current": 2,
|
||||||
|
"phase_2_current": 2,
|
||||||
|
"phase_3_current": 2,
|
||||||
|
"neutral_wire_current": 2,
|
||||||
|
"phase_1_react_power": 2,
|
||||||
|
"phase_2_react_power": 2,
|
||||||
|
"phase_3_react_power": 2,
|
||||||
|
"phase_1_apparent_power": 2,
|
||||||
|
"phase_2_apparent_power": 2,
|
||||||
|
"phase_3_apparent_power": 2,
|
||||||
|
"phase_1_pf": 1,
|
||||||
|
"phase_2_pf": 1,
|
||||||
|
"phase_3_pf": 1,
|
||||||
|
"total_active_power": 2,
|
||||||
|
"total_reactive_power": 2,
|
||||||
|
"total_apparent_power": 2,
|
||||||
|
"total_power_factor": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const multiplier = {
|
||||||
|
"phase_1_power": 1,
|
||||||
|
"phase_2_power": 1,
|
||||||
|
"phase_3_power": 1,
|
||||||
|
"total_energy": 1,
|
||||||
|
"phase_1_voltage": 100,
|
||||||
|
"phase_2_voltage": 100,
|
||||||
|
"phase_3_voltage": 100,
|
||||||
|
"phase_1_current": 1000,
|
||||||
|
"phase_2_current": 1000,
|
||||||
|
"phase_3_current": 1000,
|
||||||
|
"neutral_wire_current": 1000,
|
||||||
|
"phase_1_react_power": 1,
|
||||||
|
"phase_2_react_power": 1,
|
||||||
|
"phase_3_react_power": 1,
|
||||||
|
"phase_1_apparent_power": 1,
|
||||||
|
"phase_2_apparent_power": 1,
|
||||||
|
"phase_3_apparent_power": 1,
|
||||||
|
"phase_1_pf": 1000,
|
||||||
|
"phase_2_pf": 1000,
|
||||||
|
"phase_3_pf": 1000,
|
||||||
|
"total_active_power": 1,
|
||||||
|
"total_reactive_power": 1,
|
||||||
|
"total_apparent_power": 1,
|
||||||
|
"total_power_factor": 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
const conversionTable = {};
|
||||||
|
|
||||||
|
Object.keys(structure).map( ip => {
|
||||||
|
|
||||||
|
Object.keys(structure[ip]).map( item => {
|
||||||
|
|
||||||
|
const modul = structure[ip][item];
|
||||||
|
// console.log(modul) //i-35, i-60A ...
|
||||||
|
|
||||||
|
let section = "";
|
||||||
|
if(modul == "i-60A")
|
||||||
|
{
|
||||||
|
section = "A";
|
||||||
|
}
|
||||||
|
else if(modul == "i-60B")
|
||||||
|
{
|
||||||
|
section = "B";
|
||||||
|
}
|
||||||
|
|
||||||
|
const allRegisters = Object.keys(moduleConfigStructure[modul]);
|
||||||
|
allRegisters.map( i => {
|
||||||
|
|
||||||
|
const tb_value = moduleConfigStructure[modul][i];
|
||||||
|
const b = bytes[tb_value];
|
||||||
|
const m = multiplier[tb_value];
|
||||||
|
|
||||||
|
if(isNaN(item)) item = item.slice(0,-1);
|
||||||
|
|
||||||
|
const stream = {
|
||||||
|
"unitId": parseInt(item),
|
||||||
|
"section": section,
|
||||||
|
"name": parseInt(i),
|
||||||
|
"tb_value": tb_value,
|
||||||
|
"bytes": b,
|
||||||
|
"multiplier": m,
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tb_value == "total_energy")
|
||||||
|
{
|
||||||
|
stream.month = getCurrentMonth();
|
||||||
|
stream.previousEnergy = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(stream);
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
conversionTable[ip] = { streams: result };
|
||||||
|
// console.log(conversionTable[ip])
|
||||||
|
result = [];
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return conversionTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentMonth = () => {
|
||||||
|
const date = new Date();
|
||||||
|
return date.getMonth();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.makeStreamsTable = makeStreamsTable;
|
||||||
238
flow/httprequest.js
Normal file
238
flow/httprequest.js
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
exports.id = 'httprequest';
|
||||||
|
exports.title = 'HTTP Request';
|
||||||
|
exports.group = 'HTTP';
|
||||||
|
exports.color = '#5D9CEC';
|
||||||
|
exports.input = true;
|
||||||
|
exports.version = '2.0.6';
|
||||||
|
exports.output = 1;
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.icon = 'cloud-upload';
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div data-jc="textbox" data-jc-path="url" class="m" data-jc-config="required:true;maxlength:500;placeholder:@(E.g. https\\://www.totaljs.com)">@(URL address)</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 m">
|
||||||
|
<div data-jc="dropdown" data-jc-path="method" data-jc-config="required:true;items:,GET,POST,PUT,DELETE">@(HTTP method)</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 m">
|
||||||
|
<div data-jc="dropdown" data-jc-path="stringify" data-jc-config="required:true;items:,URL encoded|encoded,JSON|json,RAW|raw,None|none">@(Serialization)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="chunks">@(Download the content <b>in chunks</b>)</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="persistentcookies">@(Keep persistent cookies)</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="nodns">@(Disable DNS cache)</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="keepalive">@(Keep alive connection)</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="keepmessage">@(Keep message instance)</div>
|
||||||
|
</div>
|
||||||
|
<hr class="nmt nmb" />
|
||||||
|
<div class="padding">
|
||||||
|
<div data-jc="keyvalue" data-jc-path="headers" data-jc-config="placeholderkey:@(Header name);placeholdervalue:@(Header value and press enter)" class="m">@(Custom headers)</div>
|
||||||
|
<div data-jc="keyvalue" data-jc-path="cookies" data-jc-config="placeholderkey:@(Cookie name);placeholdervalue:@(Cookie value and press enter)">@(Cookies)</div>
|
||||||
|
</div>
|
||||||
|
<div class="padding bg-smoke">
|
||||||
|
<section>
|
||||||
|
<label><i class="fa fa-lock"></i>@(HTTP basic access authentication)</label>
|
||||||
|
<div class="padding npb">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 m">
|
||||||
|
<div data-jc="textbox" data-jc-path="username">@(User)</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 m">
|
||||||
|
<div data-jc="textbox" data-jc-path="userpassword">@(Password)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.readme = `# Request
|
||||||
|
|
||||||
|
This component creates a request with received data.
|
||||||
|
|
||||||
|
__Response:__
|
||||||
|
\`\`\`javascript
|
||||||
|
{
|
||||||
|
data: String,
|
||||||
|
headers: Object,
|
||||||
|
status: Number,
|
||||||
|
host: String
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
__Dynamic arguments__:
|
||||||
|
Are performed via FlowData repository and can be used for URL address or for custom headers/cookies/auth. Use \`repository\` component for creating of dynamic arguments. Dynamic values are replaced in the form \`{key}\`:
|
||||||
|
|
||||||
|
- url address e.g. \`https://.../{key}/\`
|
||||||
|
- headers values e.g. \`{token}\`
|
||||||
|
- cookies values e.g. \`{token}\``;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var can = false;
|
||||||
|
var flags = null;
|
||||||
|
var cookies2 = null;
|
||||||
|
|
||||||
|
instance.on('data', function(response) {
|
||||||
|
can && instance.custom.send(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.custom.send = function(flowdata) {
|
||||||
|
|
||||||
|
var options = instance.options;
|
||||||
|
var headers = null;
|
||||||
|
var cookies = null;
|
||||||
|
|
||||||
|
if (options.headers) {
|
||||||
|
headers = {};
|
||||||
|
for (var key in options.headers)
|
||||||
|
headers[key] = flowdata.arg(options.headers[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.username && options.userpassword) {
|
||||||
|
!headers && (headers = {});
|
||||||
|
headers.Authorization = 'Basic ' + U.createBuffer(flowdata.arg(options.username + ':' + options.userpassword)).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.cookies) {
|
||||||
|
for (var key in options.cookies) {
|
||||||
|
!cookies && (cookies = {});
|
||||||
|
cookies[key] = flowdata.arg(options.cookies[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (F.is4) {
|
||||||
|
|
||||||
|
var opt = {};
|
||||||
|
|
||||||
|
opt.method = options.method;
|
||||||
|
opt.url = options.url;
|
||||||
|
opt.headers = headers;
|
||||||
|
opt.cookies = cookies;
|
||||||
|
|
||||||
|
if (options.keepalive)
|
||||||
|
opt.keepalive = true;
|
||||||
|
|
||||||
|
opt.dnscache = options.nodns ? false : true;
|
||||||
|
|
||||||
|
if (options.chunks) {
|
||||||
|
opt.custom = true;
|
||||||
|
opt.callback = function(err, response) {
|
||||||
|
if (err)
|
||||||
|
instance.error(err);
|
||||||
|
else if (response && response.stream) {
|
||||||
|
response.stream.on('data', function(chunks) {
|
||||||
|
if (options.keepmessage) {
|
||||||
|
flowdata.data = chunks;
|
||||||
|
instance.send2(flowdata);
|
||||||
|
} else
|
||||||
|
instance.send2(chunks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
opt.callback = function(err, response) {
|
||||||
|
if (response && !err) {
|
||||||
|
var msg = { data: response.body, status: response.status, headers: response.headers, host: response.host, cookies: response.cookies };
|
||||||
|
if (options.keepmessage) {
|
||||||
|
flowdata.data = msg;
|
||||||
|
instance.send2(flowdata);
|
||||||
|
} else
|
||||||
|
instance.send2(msg);
|
||||||
|
} else if (err)
|
||||||
|
instance.error(err, response);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (options.stringify) {
|
||||||
|
case 'json':
|
||||||
|
opt.body = JSON.stringify(flowdata.data);
|
||||||
|
opt.type = 'json';
|
||||||
|
break;
|
||||||
|
case 'raw':
|
||||||
|
opt.body = flowdata.data instanceof Buffer ? flowdata.data : Buffer.from(flowdata.data);
|
||||||
|
opt.type = 'raw';
|
||||||
|
break;
|
||||||
|
case 'encoded':
|
||||||
|
if (opt.method === 'GET' || opt.method === 'HEAD') {
|
||||||
|
opt.query = U.toURLEncode(flowdata.data);
|
||||||
|
} else {
|
||||||
|
opt.body = U.toURLEncode(flowdata.data);
|
||||||
|
opt.type = 'urlencoded';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUEST(opt);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (options.chunks) {
|
||||||
|
U.download(flowdata.arg(options.url), flags, options.stringify === 'none' ? null : flowdata.data, function(err, response) {
|
||||||
|
response.on('data', function(chunks) {
|
||||||
|
if (options.keepmessage) {
|
||||||
|
flowdata.data = chunks;
|
||||||
|
instance.send2(flowdata);
|
||||||
|
} else
|
||||||
|
instance.send2(chunks);
|
||||||
|
});
|
||||||
|
}, cookies || cookies2, headers);
|
||||||
|
} else {
|
||||||
|
U.request(flowdata.arg(options.url), flags, options.stringify === 'none' ? null : flowdata.data, function(err, data, status, headers, host) {
|
||||||
|
if (flowdata && !err) {
|
||||||
|
var msg = { data: data, status: status, headers: headers, host: host };
|
||||||
|
if (options.keepmessage) {
|
||||||
|
flowdata.data = msg;
|
||||||
|
instance.send2(flowdata);
|
||||||
|
} else
|
||||||
|
instance.send2(msg);
|
||||||
|
} else if (err)
|
||||||
|
instance.error(err, flowdata);
|
||||||
|
}, cookies || cookies2, headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.reconfigure = function() {
|
||||||
|
var options = instance.options;
|
||||||
|
can = options.url && options.url && options.method && options.stringify ? true : false;
|
||||||
|
instance.status(can ? '' : 'Not configured', can ? undefined : 'red');
|
||||||
|
|
||||||
|
if (!can)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (F.is4) {
|
||||||
|
|
||||||
|
flags = {};
|
||||||
|
flags.method = options.method.toUpperCase();
|
||||||
|
|
||||||
|
if (!options.nodns)
|
||||||
|
flags.resolve = true;
|
||||||
|
|
||||||
|
flags.keepalive = options.keepalive;
|
||||||
|
|
||||||
|
if (options.stringify && options.stringify !== 'none')
|
||||||
|
options.type = options.stringify;
|
||||||
|
|
||||||
|
if (options.persistentcookies) {
|
||||||
|
flags.cook = true;
|
||||||
|
cookies2 = {};
|
||||||
|
} else
|
||||||
|
cookies2 = null;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
flags = [];
|
||||||
|
flags.push(options.method.toLowerCase());
|
||||||
|
options.stringify === 'json' && flags.push('json');
|
||||||
|
options.stringify === 'raw' && flags.push('raw');
|
||||||
|
options.keepalive && flags.push('keepalive');
|
||||||
|
!options.nodns && flags.push('dnscache');
|
||||||
|
if (options.persistentcookies) {
|
||||||
|
flags.push('cookies');
|
||||||
|
cookies2 = {};
|
||||||
|
} else
|
||||||
|
cookies2 = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('options', instance.reconfigure);
|
||||||
|
instance.reconfigure();
|
||||||
|
};
|
||||||
121
flow/infosender.js
Normal file
121
flow/infosender.js
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
exports.id = 'infosender';
|
||||||
|
exports.title = 'Info sender';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.group = 'Worksys';
|
||||||
|
exports.color = '#2134B0';
|
||||||
|
exports.input = 1;
|
||||||
|
exports.output = 1
|
||||||
|
exports.click = false;
|
||||||
|
exports.author = 'oms-is';
|
||||||
|
exports.icon = 'bolt';
|
||||||
|
exports.options = { edge: "undefined" };
|
||||||
|
|
||||||
|
const { networkInterfaces } = require('os');
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div data-jc="textbox" data-jc-path="edge" data-jc-config="placeholder:undefined;required:true" class="m">CSV Import</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.readme = `# send all data to projects.worksys.io, required to monitor status of controller(unipi)`;
|
||||||
|
|
||||||
|
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
|
||||||
|
const fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
exports.install = async function(instance) {
|
||||||
|
|
||||||
|
let id;
|
||||||
|
let allValues = {};
|
||||||
|
let dbSettings;
|
||||||
|
|
||||||
|
let sendAllValuesInterval;
|
||||||
|
|
||||||
|
let now = new Date();
|
||||||
|
console.log(exports.title, "INSTALLED", now.toLocaleString("sk-SK"));
|
||||||
|
|
||||||
|
const nets = networkInterfaces();
|
||||||
|
let ipAddresses = Object.create(null); // Or just '{}', an empty object
|
||||||
|
|
||||||
|
for (const name of Object.keys(nets)) {
|
||||||
|
for (const net of nets[name]) {
|
||||||
|
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
||||||
|
if (net.family === 'IPv4' && !net.internal) {
|
||||||
|
if (!ipAddresses[name]) {
|
||||||
|
ipAddresses[name] = [];
|
||||||
|
}
|
||||||
|
ipAddresses[name].push(net.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let p = path.join(__dirname + "/../databases/", 'settings.table');
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
|
||||||
|
dbSettings = TABLE("settings");
|
||||||
|
let responseSettings = await promisifyBuilder(dbSettings.find());
|
||||||
|
id = responseSettings[0]["projects_id"];
|
||||||
|
|
||||||
|
//console.log(exports.title, responseSettings, id);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sendValues()
|
||||||
|
{
|
||||||
|
if(Object.keys(allValues).length > 0)
|
||||||
|
{
|
||||||
|
if(id !== undefined)
|
||||||
|
{
|
||||||
|
delete allValues.__force__;
|
||||||
|
let dataToSend = {...allValues};
|
||||||
|
dataToSend.id = id;
|
||||||
|
dataToSend.ipAddresses = ipAddresses;
|
||||||
|
// dataToSend.notify_date = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
||||||
|
|
||||||
|
//console.log(exports.title, "------------>sendValues", dataToSend);
|
||||||
|
|
||||||
|
instance.send(0, dataToSend);
|
||||||
|
|
||||||
|
allValues = {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(exports.title, "unable to send data, id is undefined");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.on("close", () => {
|
||||||
|
clearInterval(sendAllValuesInterval);
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.on("data", (flowdata) => {
|
||||||
|
|
||||||
|
allValues = { ...allValues, ...flowdata.data};
|
||||||
|
|
||||||
|
//console.log("DATA RECEIVED", flowdata.data);
|
||||||
|
|
||||||
|
//__force__
|
||||||
|
if(flowdata.data.hasOwnProperty("__force__"))
|
||||||
|
{
|
||||||
|
if(flowdata.data.__force__)
|
||||||
|
{
|
||||||
|
sendValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
sendAllValuesInterval = setInterval(() => {
|
||||||
|
sendValues();
|
||||||
|
}, 60000*3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
156
flow/monitorconsumption.js
Normal file
156
flow/monitorconsumption.js
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
exports.id = 'monitorconsumption';
|
||||||
|
exports.title = 'Consumption';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.group = 'Monitoring';
|
||||||
|
exports.color = '#967ADC';
|
||||||
|
exports.input = 0;
|
||||||
|
exports.output = 1;
|
||||||
|
exports.icon = 'bug';
|
||||||
|
exports.options = { interval: 5000, enabled: true, monitorconsumption: true, monitorsize: true, monitorconnections: true, monitorfiles: true };
|
||||||
|
exports.click = true;
|
||||||
|
exports.readme = `# Consumption monitoring
|
||||||
|
|
||||||
|
This component measure CPU and memory consumption, open files and open connections of this application. It uses these Linux commands: \`ps\`, \`lsof\`, \`netstat\` and \`df\`.
|
||||||
|
|
||||||
|
__Data Example__:
|
||||||
|
|
||||||
|
\`\`\`javascript
|
||||||
|
{
|
||||||
|
cpu: 0, // percentage
|
||||||
|
memory: 4096, // in bytes
|
||||||
|
size: 34303, // directory size in bytes
|
||||||
|
files: 34, // count of open files
|
||||||
|
connections: 343, // count of connections
|
||||||
|
uptime: '1-12:34:00'
|
||||||
|
}
|
||||||
|
\`\`\``;
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 m">
|
||||||
|
<div data-jc="textbox" data-jc-path="interval" data-jc-config="placeholder:10000;increment:true;type:number;required:true;maxlength:10;align:center">@(Interval in milliseconds)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div data-jc="checkbox" data-jc-path="monitorconsumption">Monitor: Consumption + uptime</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="monitorfiles">Monitor: Count of open files</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="monitorconnections">Monitor: Count of open connections</div>
|
||||||
|
<div data-jc="checkbox" data-jc-path="monitorsize">Monitor: Directory size</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var current = { cpu: 0, memory: 0, files: 0, connections: 0, size: 0, uptime: '', counter: 0 };
|
||||||
|
var tproc = null;
|
||||||
|
var Exec = require('child_process').exec;
|
||||||
|
var reg_empty = /\s{2,}/g;
|
||||||
|
var reg_appdisksize = /^[\d.,]+/;
|
||||||
|
|
||||||
|
instance.custom.run = function() {
|
||||||
|
|
||||||
|
if (tproc) {
|
||||||
|
clearTimeout(tproc);
|
||||||
|
tproc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var arr = [];
|
||||||
|
|
||||||
|
// Get CPU and Memory consumption
|
||||||
|
instance.options.monitorconsumption && arr.push(function(next) {
|
||||||
|
Exec('ps -p {0} -o %cpu,rss,etime'.format(process.pid), function(err, response) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
instance.throw(err);
|
||||||
|
} else {
|
||||||
|
var line = response.split('\n')[1];
|
||||||
|
line = line.trim().replace(reg_empty, ' ').split(' ');
|
||||||
|
var cpu = line[0].parseFloat();
|
||||||
|
current.cpu = cpu.floor(1);
|
||||||
|
current.memory = line[1].parseInt2() * 1024; // kB to bytes
|
||||||
|
current.uptime = line[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get count of open files
|
||||||
|
instance.options.monitorfiles && arr.push(function(next) {
|
||||||
|
Exec('lsof -a -p {0} | wc -l'.format(process.pid), function(err, response) {
|
||||||
|
if (err)
|
||||||
|
instance.throw(err);
|
||||||
|
else
|
||||||
|
current.files = response.trim().parseInt2();
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get count of opened network connections
|
||||||
|
instance.options.monitorconnections && arr.push(function(next) {
|
||||||
|
Exec('netstat -an | grep :{0} | wc -l'.format(F.port), function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
instance.throw(err);
|
||||||
|
} else {
|
||||||
|
current.connections = response.trim().parseInt2() - 1;
|
||||||
|
if (current.connections < 0)
|
||||||
|
current.connections = 0;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get directory size
|
||||||
|
instance.options.monitorsize && current.counter % 5 !== 0 && arr.push(function(next) {
|
||||||
|
Exec('du -hsb ' + process.cwd(), function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
instance.throw(err);
|
||||||
|
} else {
|
||||||
|
var match = response.trim().match(reg_appdisksize);
|
||||||
|
match && (current.size = match.toString().trim().parseInt2());
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
arr.async(function() {
|
||||||
|
|
||||||
|
tproc && clearTimeout(tproc);
|
||||||
|
|
||||||
|
if (instance.options.enabled) {
|
||||||
|
tproc = setTimeout(instance.custom.run, instance.options.interval);
|
||||||
|
instance.send2(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.custom.status();
|
||||||
|
current.counter++;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.custom.status = function() {
|
||||||
|
if (instance.options.enabled)
|
||||||
|
instance.status('{0}% / {1}'.format(current.cpu, current.memory.filesize()));
|
||||||
|
else
|
||||||
|
instance.status('Disabled', 'red');
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('click', function() {
|
||||||
|
instance.options.enabled = !instance.options.enabled;
|
||||||
|
instance.custom.status();
|
||||||
|
|
||||||
|
if (instance.options.enabled) {
|
||||||
|
current.counter = 0;
|
||||||
|
instance.custom.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('close', function() {
|
||||||
|
if (tproc) {
|
||||||
|
clearTimeout(tproc);
|
||||||
|
tproc = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(instance.custom.run, 1000);
|
||||||
|
};
|
||||||
96
flow/monitordisk.js
Normal file
96
flow/monitordisk.js
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
exports.id = 'monitordisk';
|
||||||
|
exports.title = 'Disk';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.group = 'Monitoring';
|
||||||
|
exports.color = '#F6BB42';
|
||||||
|
exports.output = 1;
|
||||||
|
exports.icon = 'hdd-o';
|
||||||
|
exports.click = true;
|
||||||
|
exports.options = { interval: 8000, path: '/', enabled: true };
|
||||||
|
exports.readme = `# Disk monitoring
|
||||||
|
|
||||||
|
This component monitors disk \`bytes\` consumption in Linux systems. It uses \`df\` command.
|
||||||
|
|
||||||
|
__Data Example__:
|
||||||
|
|
||||||
|
\`\`\`javascript
|
||||||
|
{
|
||||||
|
total: 474549649408,
|
||||||
|
used: 39125245952,
|
||||||
|
free: 411294994432
|
||||||
|
}
|
||||||
|
\`\`\``;
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 m">
|
||||||
|
<div data---="textbox__interval__placeholder:10000;increment:true;type:number;required:true;maxlength:10;align:center">@(Interval in milliseconds)</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 m">
|
||||||
|
<div data---="textbox__path__placeholder:/;required:true">@(Path)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var current = { total: 0, used: 0, free: 0, path: '', type: '', percentUsed: 0 };
|
||||||
|
var tproc = null;
|
||||||
|
|
||||||
|
instance.custom.run = function() {
|
||||||
|
|
||||||
|
if (tproc) {
|
||||||
|
clearTimeout(tproc);
|
||||||
|
tproc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instance.options.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
require('child_process').exec('df -hTB1 ' + instance.options.path, function(err, response) {
|
||||||
|
|
||||||
|
tproc = setTimeout(instance.custom.run, instance.options.interval);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
instance.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.parseTerminal(function(line) {
|
||||||
|
if (line[0][0] !== '/')
|
||||||
|
return;
|
||||||
|
current.total = line[2].parseInt();
|
||||||
|
current.free = line[4].parseInt();
|
||||||
|
current.used = line[3].parseInt();
|
||||||
|
current.path = instance.options.path || '/';
|
||||||
|
current.type = line[1];
|
||||||
|
current.percentUsed = line[5];
|
||||||
|
instance.custom.status();
|
||||||
|
instance.send2(current);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.custom.status = function() {
|
||||||
|
if (instance.options.enabled)
|
||||||
|
instance.status(current.free.filesize() + ' / ' + current.total.filesize());
|
||||||
|
else
|
||||||
|
instance.status('Disabled', 'red');
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('click', function() {
|
||||||
|
instance.options.enabled = !instance.options.enabled;
|
||||||
|
instance.custom.status();
|
||||||
|
instance.options.enabled && instance.custom.run();
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('close', function() {
|
||||||
|
if (tproc) {
|
||||||
|
clearTimeout(tproc);
|
||||||
|
tproc = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(instance.custom.run, 1000);
|
||||||
|
};
|
||||||
87
flow/monitormemory.js
Normal file
87
flow/monitormemory.js
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
exports.id = 'monitormemory';
|
||||||
|
exports.title = 'Memory';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.group = 'Monitoring';
|
||||||
|
exports.color = '#F6BB42';
|
||||||
|
exports.output = 1;
|
||||||
|
exports.click = true;
|
||||||
|
exports.icon = 'microchip';
|
||||||
|
exports.options = { interval: 8000, enabled: true };
|
||||||
|
exports.readme = `# Memory monitoring
|
||||||
|
|
||||||
|
This component monitors memory \`bytes\` consumption in Linux systems. It uses \`free\` command.
|
||||||
|
|
||||||
|
__Data Example__:
|
||||||
|
|
||||||
|
\`\`\`javascript
|
||||||
|
{
|
||||||
|
total: 33558769664,
|
||||||
|
used: 1998868480,
|
||||||
|
free: 2653708288
|
||||||
|
}
|
||||||
|
\`\`\``;
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 m">
|
||||||
|
<div data-jc="textbox" data-jc-path="interval" data-jc-config="placeholder:10000;increment:true;type:number;required:true;maxlength:10;align:center">@(Interval in milliseconds)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var current = { total: 0, used: 0, free: 0 };
|
||||||
|
var tproc = null;
|
||||||
|
|
||||||
|
instance.custom.run = function() {
|
||||||
|
|
||||||
|
if (tproc) {
|
||||||
|
clearTimeout(tproc);
|
||||||
|
tproc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instance.options.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
require('child_process').exec('free -b -t', function(err, response) {
|
||||||
|
|
||||||
|
tproc = setTimeout(instance.custom.run, instance.options.interval);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
instance.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var memory = response.split('\n')[1].match(/\d+/g);
|
||||||
|
current.total = memory[0].parseInt();
|
||||||
|
current.used = memory[1].parseInt() - memory[3].parseInt();
|
||||||
|
current.free = current.total - current.used;
|
||||||
|
instance.custom.status();
|
||||||
|
instance.send2(current);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.custom.status = function() {
|
||||||
|
if (instance.options.enabled)
|
||||||
|
instance.status(current.free.filesize() + ' / ' + current.total.filesize());
|
||||||
|
else
|
||||||
|
instance.status('Disabled', 'red');
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('click', function() {
|
||||||
|
instance.options.enabled = !instance.options.enabled;
|
||||||
|
instance.custom.status();
|
||||||
|
instance.options.enabled && instance.custom.run();
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('close', function() {
|
||||||
|
if (tproc) {
|
||||||
|
clearTimeout(tproc);
|
||||||
|
tproc = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(instance.custom.run, 1000);
|
||||||
|
};
|
||||||
87
flow/timer.js
Normal file
87
flow/timer.js
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
exports.id = 'timer';
|
||||||
|
exports.title = 'Timer';
|
||||||
|
exports.version = '1.0.1';
|
||||||
|
exports.group = 'Time';
|
||||||
|
exports.color = '#F6BB42';
|
||||||
|
exports.output = 1;
|
||||||
|
exports.click = true;
|
||||||
|
exports.author = 'Peter Širka';
|
||||||
|
exports.icon = 'clock-o';
|
||||||
|
exports.options = { interval: 1000 };
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 m">
|
||||||
|
<div data-jc="textbox" data-jc-path="interval" data-jc-config="placeholder:1000;increment:true;type:number;required:true;align:center">@(Interval in milliseconds)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<section>
|
||||||
|
<label><i class="fa fa-random"></i>@(Output data)</label>
|
||||||
|
<div class="padding">
|
||||||
|
<div data-jc="dropdown" data-jc-path="datatype" data-jc-config="items:,String|string,Integer|integer,Float|float,Boolean|boolean,Date|date,Object|object,Base64 as Buffer|buffer" class="m">@(Data type (String by default))</div>
|
||||||
|
<div data-jc="textbox" data-jc-path="data" data-jc-config="placeholder:@(e.g. Hello world or { hello: 'world'} or ['hello', 'world'])">@(Data)</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.readme = `# Timer
|
||||||
|
|
||||||
|
Timer will trigger flow in the given interval (in milliseconds). You can optionally define a data-type of the output and the data.`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var value;
|
||||||
|
var id;
|
||||||
|
|
||||||
|
instance.on('click', () => value && instance.send2(value));
|
||||||
|
|
||||||
|
instance.reconfigure = function() {
|
||||||
|
var options = instance.options;
|
||||||
|
|
||||||
|
if (!options.interval) {
|
||||||
|
instance.status('Not configured', 'red');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
switch (options.datatype) {
|
||||||
|
case 'string':
|
||||||
|
value = options.data;
|
||||||
|
break;
|
||||||
|
case 'integer':
|
||||||
|
value = U.parseInt(options.data);
|
||||||
|
break;
|
||||||
|
case 'float':
|
||||||
|
value = U.parseFloat(options.data);
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
var num = U.parseInt(options.data);
|
||||||
|
value = num ? new Date(num) : options.data.parseDate();
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
try {
|
||||||
|
value = (new Function('return ' + options.data))();
|
||||||
|
} catch (e) {
|
||||||
|
instance.error(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
value = options.data.parseBoolean();
|
||||||
|
break;
|
||||||
|
case 'buffer':
|
||||||
|
try {
|
||||||
|
value = F.is4 ? Buffer.from(options.data) : U.createBuffer(options.data);
|
||||||
|
} catch (e) {
|
||||||
|
instance.error(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
clearInterval(id);
|
||||||
|
options.interval && (id = setInterval(() => instance.send2(value), options.interval));
|
||||||
|
instance.status('');
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('close', () => clearInterval(id));
|
||||||
|
instance.on('options', instance.reconfigure);
|
||||||
|
instance.reconfigure();
|
||||||
|
};
|
||||||
125
flow/timesetter.js
Normal file
125
flow/timesetter.js
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
exports.id = 'timesetter';
|
||||||
|
exports.title = 'Timesetter';
|
||||||
|
exports.group = 'Worksys';
|
||||||
|
exports.color = '#656D78';
|
||||||
|
exports.input = true;
|
||||||
|
exports.output = 1;
|
||||||
|
exports.author = 'Rastislav Kovac';
|
||||||
|
exports.icon = 'code';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.readme = `
|
||||||
|
This component can be installed just on controllers without direct internet access!
|
||||||
|
'project_id' variable needs to be set for every project!!
|
||||||
|
|
||||||
|
Timesetter sends requests once a day to service-prod01.worksys.io to get
|
||||||
|
actual date and time. It sets unipi's system timedate
|
||||||
|
`;
|
||||||
|
|
||||||
|
//! SET project_id
|
||||||
|
const project_id = 29;
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
instance.on('data', function(flowdata) {
|
||||||
|
|
||||||
|
RESTBuilder.make(function(builder) {
|
||||||
|
|
||||||
|
if(!builder) return;
|
||||||
|
|
||||||
|
builder.method('GET');
|
||||||
|
//FLOW.OMS_edge_fw_version
|
||||||
|
builder.url(`http://192.168.252.2:8004/gettime?projects_id=${project_id}`);
|
||||||
|
|
||||||
|
builder.callback(function(err, response, output) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.send(0, "RESTBuilder timedatectl response");
|
||||||
|
const res = output.response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
const obj = JSON.parse(res);
|
||||||
|
let d = new Date(obj.date);
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
//offset in minutes - convertUTCDateToLocalDate
|
||||||
|
let diffInMinutes = now.getTimezoneOffset();
|
||||||
|
//d.setMinutes( d.getMinutes() + diffInMinutes );
|
||||||
|
|
||||||
|
//let converted = convertUTCDateToLocalDate(d);
|
||||||
|
|
||||||
|
console.log("---->TimezoneOffset", diffInMinutes);
|
||||||
|
|
||||||
|
if(d instanceof Date)
|
||||||
|
{
|
||||||
|
console.log("current js date:", d, d.getHours());
|
||||||
|
|
||||||
|
let year = d.getFullYear();
|
||||||
|
let month = addZeroBefore(d.getMonth() + 1);
|
||||||
|
let day = addZeroBefore(d.getDate());
|
||||||
|
|
||||||
|
//-2 hodiny!!!!
|
||||||
|
let hours = addZeroBefore( d.getHours() );
|
||||||
|
let minutes = addZeroBefore(d.getMinutes() );
|
||||||
|
let seconds = addZeroBefore(d.getSeconds());
|
||||||
|
|
||||||
|
let timestamp = `${year}${month}${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
let dstr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
|
||||||
|
|
||||||
|
//TODO - poslat notifikaciu a nastav hw cas
|
||||||
|
//timedatectl set-timezone "Europe/Bratislava"
|
||||||
|
//hwclock --set --date="2021-08-24 15:02:00" --localtime
|
||||||
|
|
||||||
|
//https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
|
||||||
|
|
||||||
|
|
||||||
|
//timedatectl set-time "2022-04-27 09:13:00"
|
||||||
|
{
|
||||||
|
|
||||||
|
let year = d.getUTCFullYear();
|
||||||
|
let month = addZeroBefore(d.getUTCMonth() + 1);
|
||||||
|
let day = addZeroBefore(d.getUTCDate());
|
||||||
|
|
||||||
|
let hours = addZeroBefore( d.getUTCHours() );
|
||||||
|
let minutes = addZeroBefore(d.getUTCMinutes() );
|
||||||
|
let seconds = addZeroBefore(d.getUTCSeconds());
|
||||||
|
|
||||||
|
let UTCstr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
|
||||||
|
exec(`sudo timedatectl set-time "${UTCstr}"`, (err, stdout, stderr) => {
|
||||||
|
if (err || stderr) {
|
||||||
|
console.error(err);
|
||||||
|
console.log(stderr);
|
||||||
|
console.log(UTCstr);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(`UTC: timedatectl set-time "${UTCstr}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function addZeroBefore(n) {
|
||||||
|
return (n < 10 ? '0' : '') + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
79
flow/trigger.js
Normal file
79
flow/trigger.js
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
exports.id = 'trigger';
|
||||||
|
exports.title = 'Trigger';
|
||||||
|
exports.group = 'Inputs';
|
||||||
|
exports.color = '#F6BB42';
|
||||||
|
exports.click = true;
|
||||||
|
exports.output = 1;
|
||||||
|
exports.version = '1.1.1';
|
||||||
|
exports.author = 'Martin Smola';
|
||||||
|
exports.icon = 'play';
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div data-jc="dropdown__datatype__items:,String|string,Integer|integer,Float|float,Boolean|boolean,Date|date,Object|object,Base64 as Buffer|buffer" class="m">@(Data type (String by default))</div>
|
||||||
|
<div data-jc="textbox__data__placeholder:@(e.g. Hello world or { hello: 'world'} or ['hello', 'world']))" class="m">@(Data)</div>
|
||||||
|
<div data-jc="checkbox__restart">Trigger 5s after initialization.</div>
|
||||||
|
<div class="help">@(Useful when there's a need to run certain flow when the app restarts, etc.)</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
exports.readme = `# Trigger
|
||||||
|
|
||||||
|
- Clicking on the component starts the chain
|
||||||
|
- Settings allows to set a data-type and a value`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var value;
|
||||||
|
|
||||||
|
instance.on('click', () => instance.send2(value));
|
||||||
|
|
||||||
|
instance.reconfigure = function() {
|
||||||
|
var options = instance.options;
|
||||||
|
value = null;
|
||||||
|
switch (options.datatype) {
|
||||||
|
case 'integer':
|
||||||
|
value = options.data.parseInt2('error');
|
||||||
|
value = value === 'error' ? NaN : value;
|
||||||
|
break;
|
||||||
|
case 'float':
|
||||||
|
value = options.data.parseFloat2('error');
|
||||||
|
value = value === 'error' ? NaN : value;
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
options.data = options.data.toString();
|
||||||
|
var num = options.data.parseInt('error');
|
||||||
|
num === 'error' && (num = options.data.parseDate('error'));
|
||||||
|
num === 'error' && (num = null);
|
||||||
|
value = num ? new Date(num).toUTCString() : num;
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
try {
|
||||||
|
value = (new Function('return ' + options.data))();
|
||||||
|
} catch (e) {
|
||||||
|
instance.error(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
value = options.data.parseBoolean();
|
||||||
|
break;
|
||||||
|
case 'buffer':
|
||||||
|
try {
|
||||||
|
value = F.is4 ? Buffer.from(options.data) : U.createBuffer(options.data);
|
||||||
|
} catch (e) {
|
||||||
|
instance.error(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
default:
|
||||||
|
value = '' + (options.data || '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('options', instance.reconfigure);
|
||||||
|
instance.reconfigure();
|
||||||
|
|
||||||
|
if (instance.options.restart)
|
||||||
|
setTimeout(function(){
|
||||||
|
instance.send2(value);
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
0
flow/variables.txt
Normal file
0
flow/variables.txt
Normal file
43
flow/virtualwirein.js
Normal file
43
flow/virtualwirein.js
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
exports.id = 'virtualwirein';
|
||||||
|
exports.title = 'Virtual wire in';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.author = 'Martin Smola';
|
||||||
|
exports.color = '#303E4D';
|
||||||
|
exports.icon = 'sign-in';
|
||||||
|
exports.input = false;
|
||||||
|
exports.output = 1;
|
||||||
|
exports.options = {};
|
||||||
|
exports.readme = `# Virtual wire in
|
||||||
|
|
||||||
|
When the wires between the components are mess it's time to use Virtual wire.`;
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div data-jc="textbox" data-jc-path="wirename" data-jc-config="required:true;placeholder:@(some identifier)" class="m">@(Wire name)</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
ON('save.virtualwirein', function(component, options) {
|
||||||
|
!component.name && (component.name = options.wirename);
|
||||||
|
});
|
||||||
|
WATCH('settings.virtualwirein.wirename', function(path, value, type){
|
||||||
|
if (type === 2)
|
||||||
|
SET('settings.virtualwirein.wirename', value.slug());
|
||||||
|
});
|
||||||
|
</script>`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
instance.custom.reconfigure = function(){
|
||||||
|
if (instance.options.wirename) {
|
||||||
|
instance.status(instance.options.wirename);
|
||||||
|
} else
|
||||||
|
instance.status('Not configured', 'red');
|
||||||
|
};
|
||||||
|
|
||||||
|
ON('virtualwire', function(wirename, flowdata){
|
||||||
|
if (instance.options.wirename && instance.options.wirename === wirename)
|
||||||
|
instance.send(flowdata);
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('options', instance.custom.reconfigure);
|
||||||
|
instance.custom.reconfigure();
|
||||||
|
};
|
||||||
41
flow/virtualwireout.js
Normal file
41
flow/virtualwireout.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
exports.id = 'virtualwireout';
|
||||||
|
exports.title = 'Virtual wire out';
|
||||||
|
exports.version = '1.0.0';
|
||||||
|
exports.author = 'Martin Smola';
|
||||||
|
exports.color = '#303E4D';
|
||||||
|
exports.icon = 'sign-out';
|
||||||
|
exports.input = true;
|
||||||
|
exports.options = {};
|
||||||
|
exports.readme = `# Virtual wire out
|
||||||
|
|
||||||
|
When the wires between the components are mess it's time to use Virtual wire.`;
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div data-jc="textbox" data-jc-path="wirename" class="m" data-jc-config="required:true;placeholder:@(some identifier)">@(Wire name)</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
ON('save.virtualwireout', function(component, options) {
|
||||||
|
!component.name && (component.name = options.wirename);
|
||||||
|
});
|
||||||
|
WATCH('settings.virtualwireout.wirename', function(path, value, type){
|
||||||
|
if (type === 2)
|
||||||
|
SET('settings.virtualwireout.wirename', value.slug());
|
||||||
|
});
|
||||||
|
</script>`;
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
instance.custom.reconfigure = function(){
|
||||||
|
if (instance.options.wirename) {
|
||||||
|
instance.status(instance.options.wirename);
|
||||||
|
} else
|
||||||
|
instance.status('Not configured', 'red');
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.on('data', function(flowdata) {
|
||||||
|
EMIT('virtualwire', instance.options.wirename, flowdata);
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.on('options', instance.custom.reconfigure);
|
||||||
|
instance.custom.reconfigure();
|
||||||
|
};
|
||||||
549
flow/wsmqttpublish.js
Normal file
549
flow/wsmqttpublish.js
Normal file
|
|
@ -0,0 +1,549 @@
|
||||||
|
exports.id = 'wsmqttpublish';
|
||||||
|
exports.title = 'WS MQTT publish';
|
||||||
|
exports.group = 'MQTT';
|
||||||
|
exports.color = '#888600';
|
||||||
|
exports.version = '1.0.2';
|
||||||
|
exports.icon = 'sign-out';
|
||||||
|
exports.input = 1;
|
||||||
|
exports.output = ["red", "white", "blue"];
|
||||||
|
exports.author = 'Daniel Segeš';
|
||||||
|
exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" };
|
||||||
|
exports.npm = ['mqtt'];
|
||||||
|
|
||||||
|
|
||||||
|
exports.html = `<div class="padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div data-jc="textbox" data-jc-path="host" data-jc-config="placeholder:test.mosquitto.org;required:false" class="m">Hostname or IP address (if not empty - setting will override db setting)</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div data-jc="textbox" data-jc-path="port" data-jc-config="placeholder:1883;required:true" class="m">Port</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div data-jc="textbox" data-jc-path="clientid">@(Client id)</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div data-jc="textbox" data-jc-path="username" class="m">@(Username)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
|
||||||
|
exports.readme = `
|
||||||
|
# WS MQTT Publish
|
||||||
|
|
||||||
|
Version 1.0.3.
|
||||||
|
|
||||||
|
Added:
|
||||||
|
- database collections,
|
||||||
|
- rpc response
|
||||||
|
`;
|
||||||
|
|
||||||
|
const instanceSendTo = {
|
||||||
|
debug: 0,
|
||||||
|
rpcCall: 1,
|
||||||
|
services: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
|
||||||
|
|
||||||
|
//CONFIG
|
||||||
|
let useLog4js = true;
|
||||||
|
let createTelemetryBackup = true;
|
||||||
|
let saveTelemetryOnError = true;//overrides backup_on_failure
|
||||||
|
//------------------------
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
let rollers;
|
||||||
|
if(createTelemetryBackup) rollers = require('streamroller');
|
||||||
|
|
||||||
|
const noSqlFileSizeLimit = 4194304;//use 5MB - 4194304
|
||||||
|
let insertNoSqlCounter = 0;
|
||||||
|
let insertBackupNoSqlCounter = 0;
|
||||||
|
let processingData = false;
|
||||||
|
|
||||||
|
let backup_on_failure = true;//== saveTelemetryOnError - create backup broker send failure
|
||||||
|
let restore_from_backup = 100; //how many rows process at once?
|
||||||
|
let restore_backup_wait = 5;//wait seconds
|
||||||
|
let lastRestoreTime = 0;
|
||||||
|
|
||||||
|
let errLogger;
|
||||||
|
let logger;
|
||||||
|
let monitor;
|
||||||
|
|
||||||
|
if(useLog4js)
|
||||||
|
{
|
||||||
|
var path = require('path');
|
||||||
|
var log4js = require("log4js");
|
||||||
|
|
||||||
|
log4js.configure({
|
||||||
|
appenders: {
|
||||||
|
errLogs: { type: 'file', filename: path.join(__dirname + "/../", 'err.txt') },
|
||||||
|
monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
|
||||||
|
console: { type: 'console' }
|
||||||
|
},
|
||||||
|
categories: {
|
||||||
|
errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
|
||||||
|
monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
|
||||||
|
//another: { appenders: ['console'], level: 'trace' },
|
||||||
|
default: { appenders: ['console'], level: 'trace' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
errLogger = log4js.getLogger("errLogs");
|
||||||
|
logger = log4js.getLogger();
|
||||||
|
monitor = log4js.getLogger("monitorLogs");
|
||||||
|
|
||||||
|
//USAGE
|
||||||
|
//logger.debug("text");
|
||||||
|
//monitor.info('info');
|
||||||
|
//errLogger.error("some error");
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('uncaughtException', function (err) {
|
||||||
|
|
||||||
|
if(errLogger)
|
||||||
|
{
|
||||||
|
errLogger.error('uncaughtException:', err.message)
|
||||||
|
errLogger.error(err.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//send to service
|
||||||
|
|
||||||
|
//process.exit(1);
|
||||||
|
})
|
||||||
|
|
||||||
|
const nosql = NOSQL('tbdata');
|
||||||
|
const nosqlBackup = NOSQL('/backup/tbdata');
|
||||||
|
|
||||||
|
exports.install = function(instance) {
|
||||||
|
|
||||||
|
var broker;
|
||||||
|
var opts;
|
||||||
|
var brokerready = false;
|
||||||
|
|
||||||
|
instance.on('options', loadSettings);
|
||||||
|
|
||||||
|
mqtt = require('mqtt');
|
||||||
|
|
||||||
|
// wsmqtt status for notification purposes on projects.worksys.io database
|
||||||
|
let wsmqttName = null;
|
||||||
|
let sendWsStatusVar = null;
|
||||||
|
let wsmqtt_status = 'disconnected';
|
||||||
|
|
||||||
|
function getWsmqttName(host)
|
||||||
|
{
|
||||||
|
if(host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
|
||||||
|
else if(host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
|
||||||
|
else if(host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendWsStatus()
|
||||||
|
{
|
||||||
|
instance.send(instanceSendTo.services, {[wsmqttName]: wsmqtt_status});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendWsStatusVar = setInterval(sendWsStatus, 180000);
|
||||||
|
|
||||||
|
|
||||||
|
//set opts according to db settings
|
||||||
|
async function loadSettings()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(instance.options.host !== "")
|
||||||
|
{
|
||||||
|
//override settings from database
|
||||||
|
var o = instance.options;
|
||||||
|
opts = {
|
||||||
|
host: o.host,
|
||||||
|
port: o.port,
|
||||||
|
clientId: o.clientid,
|
||||||
|
username: o.username,
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
resubscribe: false
|
||||||
|
};
|
||||||
|
|
||||||
|
wsmqttName = getWsmqttName(o.host);
|
||||||
|
|
||||||
|
console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
const dbSettings = TABLE("settings");
|
||||||
|
let responseSettings = await promisifyBuilder(dbSettings.find());
|
||||||
|
|
||||||
|
backup_on_failure = responseSettings[0]["backup_on_failure"];
|
||||||
|
saveTelemetryOnError = backup_on_failure;
|
||||||
|
|
||||||
|
restore_from_backup = responseSettings[0]["restore_from_backup"];
|
||||||
|
restore_backup_wait = responseSettings[0]["restore_backup_wait"];
|
||||||
|
|
||||||
|
let mqtt_host = responseSettings[0]["mqtt_host"];
|
||||||
|
let mqtt_clientid = responseSettings[0]["mqtt_clientid"];
|
||||||
|
let mqtt_username = responseSettings[0]["mqtt_username"];
|
||||||
|
let mqtt_port = responseSettings[0]["mqtt_port"];
|
||||||
|
|
||||||
|
console.log("wsmqttpublich -> loadSettings from db", responseSettings[0]);
|
||||||
|
|
||||||
|
opts = {
|
||||||
|
host: mqtt_host,
|
||||||
|
port: mqtt_port,
|
||||||
|
keepalive: 10,
|
||||||
|
clientId: mqtt_clientid,
|
||||||
|
username: mqtt_username,
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
resubscribe: false
|
||||||
|
};
|
||||||
|
|
||||||
|
wsmqttName = getWsmqttName(mqtt_host);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectToTbServer();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectToTbServer()
|
||||||
|
{
|
||||||
|
var url = "mqtt://" + opts.host + ":" + opts.port;
|
||||||
|
console.log("MQTT URL: ", url);
|
||||||
|
|
||||||
|
broker = mqtt.connect(url, opts);
|
||||||
|
|
||||||
|
broker.on('connect', function() {
|
||||||
|
instance.status("Connected", "green");
|
||||||
|
brokerready = true;
|
||||||
|
FLOW.OMS_brokerready = brokerready;
|
||||||
|
wsmqtt_status = 'connected';
|
||||||
|
});
|
||||||
|
|
||||||
|
broker.on('reconnect', function() {
|
||||||
|
instance.status("Reconnecting", "yellow");
|
||||||
|
brokerready = false;
|
||||||
|
|
||||||
|
FLOW.OMS_brokerready = brokerready;
|
||||||
|
});
|
||||||
|
|
||||||
|
broker.on('message', function(topic, message) {
|
||||||
|
// message is type of buffer
|
||||||
|
message = message.toString();
|
||||||
|
if (message[0] === '{') {
|
||||||
|
TRY(function() {
|
||||||
|
|
||||||
|
message = JSON.parse(message);
|
||||||
|
if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
|
||||||
|
broker.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1});
|
||||||
|
instance.send(instanceSendTo.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}});
|
||||||
|
}
|
||||||
|
|
||||||
|
}, () => instance.debug('MQTT: Error parsing data', message));
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message });
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
broker.on('close', function(err) {
|
||||||
|
brokerready = false;
|
||||||
|
FLOW.OMS_brokerready = brokerready;
|
||||||
|
wsmqtt_status = 'disconnected';
|
||||||
|
|
||||||
|
if (err && err.toString().indexOf('Error')) {
|
||||||
|
instance.status("Err: "+err.code, "red");
|
||||||
|
instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
|
||||||
|
} else {
|
||||||
|
instance.status("Disconnected", "red");
|
||||||
|
instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
broker.on('error', function(err) {
|
||||||
|
instance.status("Err: "+ err.code, "red");
|
||||||
|
instance.send(instanceSendTo.debug, {"message":"Broker ERROR signal received !", "error":err, "opt":opts });
|
||||||
|
|
||||||
|
brokerready = false;
|
||||||
|
FLOW.OMS_brokerready = brokerready;
|
||||||
|
wsmqtt_status = 'disconnected';
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
//broker = new Broker(opts);
|
||||||
|
//MQTT_BROKERS.push(broker);
|
||||||
|
|
||||||
|
//instance.status('Ready');
|
||||||
|
}
|
||||||
|
|
||||||
|
//set opts accortding to options
|
||||||
|
/*
|
||||||
|
instance.reconfigure = function() {
|
||||||
|
|
||||||
|
|
||||||
|
var o = instance.options;
|
||||||
|
opts = {
|
||||||
|
host: o.host,
|
||||||
|
port: o.port,
|
||||||
|
keepalive: 10,
|
||||||
|
clientId: o.clientid,
|
||||||
|
username: o.username,
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
resubscribe: false
|
||||||
|
};
|
||||||
|
|
||||||
|
//connectToTbServer();
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
instance.on('data', function(data) {
|
||||||
|
|
||||||
|
if (brokerready)
|
||||||
|
{
|
||||||
|
//do we have some data in backup file?
|
||||||
|
//if any, process data from database
|
||||||
|
if(saveTelemetryOnError)
|
||||||
|
{
|
||||||
|
//read telemetry data and send back to server
|
||||||
|
if(!processingData) processDataFromDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brokerready)
|
||||||
|
{
|
||||||
|
let stringifiedJson = JSON.stringify(data.data);
|
||||||
|
broker.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1});
|
||||||
|
|
||||||
|
//backup telemetry
|
||||||
|
//{"2O14VBzl8aDmWdNw3A53vOkGyZ5qLJoEMpj6R9ng":[{"ts":1658619104272,"values":{"status":"OK","total_reactive_power":-31}}]}
|
||||||
|
let key = Object.keys(data.data)[0];
|
||||||
|
let o = data.data[key][0].values;
|
||||||
|
|
||||||
|
if(o.hasOwnProperty('total_energy'))
|
||||||
|
{
|
||||||
|
if(createTelemetryBackup)
|
||||||
|
{
|
||||||
|
data.data.id = UID();
|
||||||
|
nosqlBackup.insert(data.data);
|
||||||
|
|
||||||
|
insertBackupNoSqlCounter++;
|
||||||
|
if(insertBackupNoSqlCounter > 150)
|
||||||
|
{
|
||||||
|
let options = {compress: true};
|
||||||
|
let path = __dirname + "/../databases/backup/tbdata.nosql";
|
||||||
|
var stream = new rollers.RollingFileStream(path, noSqlFileSizeLimit, 150, options);
|
||||||
|
stream.write("");
|
||||||
|
stream.end();
|
||||||
|
|
||||||
|
insertBackupNoSqlCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if(logger) logger.debug("Broker unavailable. Data not sent !", data.data);
|
||||||
|
instance.send(instanceSendTo.debug, {"message":"Broker unavailable. Data not sent !", "data": data.data });
|
||||||
|
|
||||||
|
if(saveTelemetryOnError)
|
||||||
|
{
|
||||||
|
//create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
|
||||||
|
makeBackupFromDbFile();
|
||||||
|
|
||||||
|
//write to tb
|
||||||
|
data.data.id = UID();
|
||||||
|
nosql.insert(data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.close = function(done) {
|
||||||
|
if (brokerready){
|
||||||
|
broker.end();
|
||||||
|
clearInterval(sendWsStatusVar);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function getDbBackupFileCounter(type)
|
||||||
|
{
|
||||||
|
var files = fs.readdirSync(__dirname + "/../databases");
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
for(var i = 0; i < files.length; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(files[i] == "tbdata.nosql") continue;
|
||||||
|
|
||||||
|
if(files[i].endsWith(".nosql"))
|
||||||
|
{
|
||||||
|
|
||||||
|
let pos = files[i].indexOf(".");
|
||||||
|
if(pos > -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
let fileCounter = counter;
|
||||||
|
let firstDigit = files[i].slice(0, pos);
|
||||||
|
|
||||||
|
fileCounter = parseInt(firstDigit);
|
||||||
|
if (isNaN(fileCounter)) fileCounter = 0;
|
||||||
|
//console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
|
||||||
|
|
||||||
|
if(type == "max")
|
||||||
|
{
|
||||||
|
if(fileCounter > counter)
|
||||||
|
{
|
||||||
|
counter = fileCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type == "min")
|
||||||
|
{
|
||||||
|
if(counter == 0) counter = fileCounter;
|
||||||
|
|
||||||
|
if(fileCounter < counter)
|
||||||
|
{
|
||||||
|
counter = fileCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == "max") counter++;
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeBackupFromDbFile = async () => {
|
||||||
|
|
||||||
|
if(!saveTelemetryOnError) return;
|
||||||
|
|
||||||
|
//to avoid large file: tbdata.nosql
|
||||||
|
|
||||||
|
//init value is 0!
|
||||||
|
if(insertNoSqlCounter > 0)
|
||||||
|
{
|
||||||
|
--insertNoSqlCounter;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertNoSqlCounter = 100;
|
||||||
|
|
||||||
|
let source = __dirname + "/../databases/tbdata.nosql";
|
||||||
|
|
||||||
|
var stats = fs.statSync(source);
|
||||||
|
var fileSizeInBytes = stats.size;
|
||||||
|
|
||||||
|
if(fileSizeInBytes > noSqlFileSizeLimit)
|
||||||
|
{
|
||||||
|
|
||||||
|
let counter = 1;
|
||||||
|
counter = getDbBackupFileCounter("max");
|
||||||
|
|
||||||
|
let destination = __dirname + "/../databases/" + counter + "." + "tbdata.nosql";
|
||||||
|
|
||||||
|
//make backup file
|
||||||
|
fs.copyFileSync(source, destination);
|
||||||
|
//fs.renameSync(p, p + "." + counter);
|
||||||
|
|
||||||
|
//clear tbdata.nosql
|
||||||
|
fs.writeFileSync(source, "");
|
||||||
|
fs.truncateSync(source, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const processDataFromDatabase = async () => {
|
||||||
|
|
||||||
|
if(restore_from_backup <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate diff
|
||||||
|
const now = new Date();
|
||||||
|
let currentTime = now.getTime();
|
||||||
|
let diff = currentTime - lastRestoreTime;
|
||||||
|
|
||||||
|
if( (diff / 1000) < restore_backup_wait)
|
||||||
|
{
|
||||||
|
//console.log("*********restore_backup_wait", diff, restore_backup_wait);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processingData = true;
|
||||||
|
|
||||||
|
//get filename to process
|
||||||
|
let counter = getDbBackupFileCounter("min");
|
||||||
|
|
||||||
|
//we have some backup files
|
||||||
|
let dataBase = 'tbdata';
|
||||||
|
|
||||||
|
var nosql;
|
||||||
|
if(counter == 0) dataBase = 'tbdata';
|
||||||
|
else dataBase = counter + "." + 'tbdata';
|
||||||
|
|
||||||
|
nosql = NOSQL(dataBase);
|
||||||
|
|
||||||
|
//select all data - use limit restore_from_backup
|
||||||
|
let records = await promisifyBuilder(nosql.find().take(restore_from_backup));
|
||||||
|
|
||||||
|
for(let i = 0; i < records.length; i++)
|
||||||
|
{
|
||||||
|
if (brokerready) {
|
||||||
|
|
||||||
|
let item = records[i];
|
||||||
|
let id = item.id;
|
||||||
|
|
||||||
|
if(id !== undefined)
|
||||||
|
{
|
||||||
|
//console.log("------------processDataFromDatabase - remove", id, dataBase, i);
|
||||||
|
|
||||||
|
let o = JSON.parse(JSON.stringify(item));
|
||||||
|
delete o.id;
|
||||||
|
let message = JSON.stringify(o);
|
||||||
|
|
||||||
|
broker.publish("v1/gateway/telemetry", message, {qos:1});
|
||||||
|
|
||||||
|
//remove from database
|
||||||
|
await promisifyBuilder(nosql.remove().where("id", id));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
processingData = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(records.length > 0)
|
||||||
|
{
|
||||||
|
//clean backup file
|
||||||
|
if(counter > 0) nosql.clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
//no data in db, remove
|
||||||
|
if(records.length == 0)
|
||||||
|
{
|
||||||
|
if(counter > 0) nosql.drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const d = new Date();
|
||||||
|
lastRestoreTime = d.getTime();
|
||||||
|
|
||||||
|
processingData = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
|
//instance.on('options', instance.reconfigure);
|
||||||
|
//instance.reconfigure();
|
||||||
|
};
|
||||||
28
package.json
Normal file
28
package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "totalproject",
|
||||||
|
"description": "Empty project",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"bitwise": "^2.1.0",
|
||||||
|
"easy-crc": "^0.0.2",
|
||||||
|
"jsmodbus": "^4.0.6",
|
||||||
|
"log4js": "^6.3.0",
|
||||||
|
"mosca": "^2.8.3",
|
||||||
|
"mqtt": "^4.2.8",
|
||||||
|
"node-schedule": "^2.0.0",
|
||||||
|
"nodemailer": "^6.7.0",
|
||||||
|
"serialport": "^9.2.4",
|
||||||
|
"total.js": "^3.4.10",
|
||||||
|
"total4": "^0.0.51"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"empty",
|
||||||
|
"project"
|
||||||
|
],
|
||||||
|
"author": "Peter Širka",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue