Compare commits
10 commits
613d846dbe
...
1012544193
| Author | SHA1 | Date | |
|---|---|---|---|
| 1012544193 | |||
| 5540cee8ec | |||
| 0c993f50b1 | |||
| 0876e73c68 | |||
| d97d90cf95 | |||
| 5233aa38af | |||
| 73a2620add | |||
| 4c59ccd095 | |||
| fad53c9c01 | |||
| 75bb2794d2 |
23 changed files with 4802 additions and 1891 deletions
36
addSwitch.py
Normal file
36
addSwitch.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import os
|
||||
|
||||
def process_set_file():
|
||||
"""
|
||||
Checks if /root/flowserver exists, reads set.txt, and modifies the second line.
|
||||
"""
|
||||
default_folder = "/root/flowserver" if os.path.exists("/root/flowserver") else "/home/unipi/flowserver"
|
||||
flag = 1 if default_folder == "/root/flowserver" else 0
|
||||
|
||||
try:
|
||||
with open("/home/unipi/flowserver/databases/settings.table", "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
if len(lines) >= 2:
|
||||
lines[0] = lines[0].rstrip('\n') + "|has_main_switch:boolean\n"
|
||||
second_line = lines[1].strip() # remove trailing newline
|
||||
last_pipe_index = second_line.rfind("|")
|
||||
|
||||
if last_pipe_index != -1:
|
||||
modified_line = second_line[:last_pipe_index + 1] + str(flag) + "|" + second_line[last_pipe_index + 1:]
|
||||
lines[1] = modified_line
|
||||
else:
|
||||
print("Warning: No '|' character found in the second line of set.txt")
|
||||
|
||||
with open("/home/unipi/flowserver/databases/settings.table", "w") as f:
|
||||
f.writelines(lines)
|
||||
else:
|
||||
print("Warning: settings.table has less than two lines.")
|
||||
|
||||
except FileNotFoundError:
|
||||
print("Error: settings.table not found.")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
# if __name__ == "__main__":
|
||||
process_set_file()
|
||||
2
config
2
config
|
|
@ -7,6 +7,6 @@ package#flow (Object) : { url: '/' }
|
|||
|
||||
table.relays : line:number|tbname:string|contactor:number|profile:string
|
||||
table.nodes : node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean|time_of_last_communication:number
|
||||
table.settings : rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|project_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number|cloud_topic:string
|
||||
table.settings : rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|project_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number|cloud_topic:string|has_main_switch:boolean
|
||||
table.pins : pin:string|type:string|line:number
|
||||
table.notifications : key:string|weight:string|sk:string|en:string
|
||||
|
|
|
|||
3055
databases/accelerometer_db.js
Normal file
3055
databases/accelerometer_db.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,2 +1,2 @@
|
|||
node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean|time_of_last_communication:number
|
||||
+|638|rDbQ84xzwgdqEoPm3kbJQWk9anOZY1RXyBv2LVM6|3|{"intervals":[{"cct":3000,"value":20,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":20,"end_time":"13:00","start_time":"05:30"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|0|1725885127396|............................................................................................................................................................................................................................................................|.................
|
||||
+|638|rDbQ84xzwgdqEoPm3kbJQWk9anOZY1RXyBv2LVM6|3|{"intervals":[{"cct":3000,"value":20,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":20,"end_time":"13:00","start_time":"05:30"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|0|1725885127396|............................................................................................................................................................................................................................................................
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ key:string|weight:string|sk:string|en:string
|
|||
+|power_supply_works_correctly|NOTICE|Napájací zdroj pracuje správne|Power supply works correctly|...............
|
||||
+|battery_level_is_low|ERROR|Batéria má nízku úroveň napätia|Battery level is low|...............
|
||||
+|battery_level_is_ok|NOTICE|Batéria má správnu úroveň napätia|Battery level is OK|...............
|
||||
+|door_opened|NOTICE|Dvere boli otvorené|Door has been opeed|...............
|
||||
+|door_closed|NOTICE|Dvere boli zatvorené|Door has been closed|...............
|
||||
+|door_opened_without_permission|WARNING|Dvere boli otvorené bez povolenia - zapnutá siréna|Door opened without permision - alarm is on|...............
|
||||
+|door_main_open|NOTICE|Hlavné dvere boli otvorené|Main door has been opened|...............
|
||||
+|door_em_open|NOTICE|Dvere silovej časti boli otvorené|Power door has been opened|...............
|
||||
+|door_main_open_without_permission|WARNING|Hlavné dvere boli otvorené bez povolenia - zapnutá siréna|Main door has been opened without permission - alarm is on|...............
|
||||
+|door_em_open_without_permission|WARNING|Dvere silovej časti boli otvorené bez povolenia|Power door has been opened without permission|...............
|
||||
+|door_main_close|NOTICE|Hlavné dvere boli zatvorené|Main door has been closed|...............
|
||||
+|door_em_close|NOTICE|Dvere silovej časti boli zatvorené|Power door has been closed|...............
|
||||
+|state_of_contactor_for_line|INFORMATIONAL|Stav stýkača pre líniu č. ${line} je ${value}|State of contactor for line no. ${line} is ${value}|...............
|
||||
+|local_database_is_corrupted|CRITICAL|||...............
|
||||
+|electrometer_nok|ERROR|Elektromer neodpovedá|Electrometer is not responding|...............
|
||||
|
|
@ -34,5 +37,5 @@ key:string|weight:string|sk:string|en:string
|
|||
+|twilight_sensor_ok|NOTICE|Sensor súmraku znovu odpovedá|Twilight sensor is responding again|...............
|
||||
+|lamps_have_turned_on|NOTICE|Lampy sa zapli|Lamps have turned on|...............
|
||||
+|lamps_have_turned_off|NOTICE|Lampy sa vypli|Lamps have turned off|...............
|
||||
+|flow_restart|NOTICE|Restart flowu|Flow has been restarted|...............
|
||||
+|nodes_db_changed|NOTICE|Zmena v node databaze|Node db has changed|...............
|
||||
+|flow_restart|NOTICE|FLOW bol reštartovaný|FLOW has been restarted|...............
|
||||
+|nodes_db_changed|NOTICE|Zmena v node databáze|Node db has changed|...............
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|project_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number|cloud_topic:string
|
||||
+|rvo_senica_22_ip10.0.0.109|en|28.F46E9D0E0000|48.70826502|17.28455203|192.168.252.1|rvo_senica_22_ip10.0.0.109|9excvr7yBcF3gl3kYZGY|1883|0|48|unipi|ttyUSB0|1|20|5|6|3|u109|...........................................
|
||||
rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|project_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number|cloud_topic:string|has_main_switch:boolean
|
||||
+|rvo_senica_22_ip10.0.0.109|en|28.F46E9D0E0000|48.70826502|17.28455203|192.168.252.1|rvo_senica_22_ip10.0.0.109|9excvr7yBcF3gl3kYZGY|1883|0|48|unipi|ttyUSB0|1|20|5|6|3|u109|0|...........................................
|
||||
|
|
|
|||
37
databases/total_energy.js
Normal file
37
databases/total_energy.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
//key is rvo_number, value is max energy when lamps are on
|
||||
const total_energy = {
|
||||
1: 580,
|
||||
2: 1100,
|
||||
3: 3700,
|
||||
4: 4100,
|
||||
7: 360,
|
||||
12: 1700,
|
||||
13: 5400,
|
||||
14: 440,
|
||||
15: 6100,
|
||||
16: 4800,
|
||||
20: 1600,
|
||||
21: 1000,
|
||||
22: 2600,
|
||||
23: 1000,
|
||||
25: 2600,
|
||||
33: 240,
|
||||
34: 4000,
|
||||
35: 2700,
|
||||
36: 820,
|
||||
37: 1400,
|
||||
35: 3500,
|
||||
39: 1170,
|
||||
41: 740,
|
||||
42: 660,
|
||||
43: 4900,
|
||||
45: 930,
|
||||
46: 700,
|
||||
47: 1100,
|
||||
48: 1500,
|
||||
50: 3200,
|
||||
55: 1000,
|
||||
56: 5500
|
||||
}
|
||||
|
||||
module.exports = total_energy;
|
||||
File diff suppressed because it is too large
Load diff
60
flow/count.js
Normal file
60
flow/count.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
exports.id = 'count';
|
||||
exports.title = 'Count';
|
||||
exports.version = '1.0.1';
|
||||
exports.author = 'John Graves';
|
||||
exports.color = '#656D78';
|
||||
exports.icon = 'plus-square';
|
||||
exports.input = 2;
|
||||
exports.output = 1;
|
||||
exports.options = { increment: 1, initialvalue: 1 };
|
||||
exports.readme = `# Counter
|
||||
|
||||
Counter Number of times called.`;
|
||||
|
||||
exports.html = `<div class="padding">
|
||||
<div data-jc="textbox" data-jc-path="initialvalue" data-jc-config="placeholder:1;increment:true;type:number;align:center">@(Initial Value)</div>
|
||||
<div data-jc="textbox" data-jc-path="increment" data-jc-config="placeholder:1;increment:true;type:number;align:center">@(Increment)</div>
|
||||
<p><a href="https://youtu.be/NuUbTm1oRE0" target="_blank">Example Video</a></p>
|
||||
</div>`;
|
||||
|
||||
exports.readme = `# Count
|
||||
|
||||
This component counts the number of messages received.
|
||||
|
||||
__Response:__
|
||||
|
||||
Integer value based on the initial value and increment settings.
|
||||
|
||||
__Arguments:__
|
||||
- Initial Value: What number should be output on the receipt of the first message.
|
||||
- Increment: What should the increment be for each following message received.`;
|
||||
|
||||
exports.install = function(instance) {
|
||||
|
||||
var count = 0;
|
||||
var initialCall = true;
|
||||
|
||||
instance.on('data', function(flowdata) {
|
||||
var index = flowdata.index;
|
||||
if (index) {
|
||||
instance.debug('Reset Count.');
|
||||
count = instance.options.initialvalue;
|
||||
initialCall = true;
|
||||
} else {
|
||||
// If this is the first time, set the value to 'initial value'
|
||||
if(initialCall) {
|
||||
initialCall = false;
|
||||
count = instance.options.initialvalue;
|
||||
} else
|
||||
count = count+instance.options.increment;
|
||||
instance.status('Count:' + count);
|
||||
instance.send2(count);
|
||||
}
|
||||
});
|
||||
|
||||
instance.on('options', function() {
|
||||
count = instance.options.initialvalue;
|
||||
initialCall = true;
|
||||
});
|
||||
|
||||
};
|
||||
165
flow/db_init.js
165
flow/db_init.js
|
|
@ -4,103 +4,106 @@ exports.group = 'Worksys';
|
|||
exports.color = '#888600';
|
||||
exports.version = '1.0.2';
|
||||
exports.icon = 'sign-out';
|
||||
exports.input = 1;
|
||||
exports.output = ["blue"];
|
||||
|
||||
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.output = 2;
|
||||
|
||||
exports.readme = `
|
||||
# DB initialization
|
||||
# DB initialization
|
||||
`;
|
||||
|
||||
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
|
||||
const { initNotification } = require('./helper/notification_reporter');
|
||||
const errorHandler = require('./helper/ErrorToServiceHandler');
|
||||
const total_energy = require('../databases/total_energy');
|
||||
|
||||
const SEND_TO = {
|
||||
db_init: 0,
|
||||
infoSender: 1
|
||||
};
|
||||
|
||||
|
||||
exports.install = async function(instance) {
|
||||
const dbNodes = TABLE("nodes");
|
||||
const dbRelays = TABLE("relays");
|
||||
const dbSettings = TABLE("settings");
|
||||
const dbPins = TABLE("pins");
|
||||
const dbNotifications = TABLE("notifications");
|
||||
|
||||
const dbNodes = TABLE("nodes");
|
||||
const dbRelays = TABLE("relays");
|
||||
const dbSettings = TABLE("settings");
|
||||
const dbPins = TABLE("pins");
|
||||
const dbNotifications = TABLE("notifications");
|
||||
FLOW.GLOBALS = {};
|
||||
const dbs = FLOW.GLOBALS;
|
||||
|
||||
FLOW.GLOBALS = {};
|
||||
const dbs = FLOW.GLOBALS;
|
||||
const responseSettings = await promisifyBuilder(dbSettings.find());
|
||||
const responseNodes = await promisifyBuilder(dbNodes.find());
|
||||
const responsePins = await promisifyBuilder(dbPins.find());
|
||||
const responseRelays = await promisifyBuilder(dbRelays.find());
|
||||
const response = await promisifyBuilder(dbNotifications.find());
|
||||
|
||||
const responseSettings = await promisifyBuilder(dbSettings.find());
|
||||
const responseNodes = await promisifyBuilder(dbNodes.find());
|
||||
const responsePins = await promisifyBuilder(dbPins.find());
|
||||
const responseRelays = await promisifyBuilder(dbRelays.find());
|
||||
const response = await promisifyBuilder(dbNotifications.find());
|
||||
dbs.pinsData = makeMapFromDbResult(responsePins, "pin");
|
||||
dbs.relaysData = makeMapFromDbResult(responseRelays, "line");
|
||||
dbs.nodesData = makeMapFromDbResult(responseNodes, "node");
|
||||
dbs.notificationsData = makeMapFromDbResult(response, "key");
|
||||
|
||||
dbs.pinsData = makeMapFromDbResult(responsePins, "pin");
|
||||
dbs.relaysData = makeMapFromDbResult(responseRelays, "line");
|
||||
dbs.nodesData = makeMapFromDbResult(responseNodes, "node");
|
||||
dbs.notificationsData = makeMapFromDbResult(response, "key");
|
||||
//+|354|nodesdata.....+|482|nodesdata....
|
||||
//for some reason, if last line in nodes.table is not empty, flow wrote more nodes data in one row,
|
||||
//so we have to add empty line at the bottom of nodes table to avoid this.
|
||||
//now, remove empty lines from nodesData database:
|
||||
if (dbs.nodesData.hasOwnProperty("0")) delete dbs.nodesData["0"];
|
||||
Object.keys(dbs.nodesData).forEach(node => dbs.nodesData[node].readout = {})
|
||||
|
||||
//+|354|nodesdata.....+|482|nodesdata....
|
||||
//for some reason, if last line in nodes.table is not empty, flow wrote more nodes data in one row,
|
||||
//so we have to add empty line at the bottom of nodes table to avoid this.
|
||||
//now, remove empty lines from nodesData database:
|
||||
if(dbs.nodesData.hasOwnProperty("0")) delete dbs.nodesData["0"];
|
||||
dbs.settings = {
|
||||
edge_fw_version: "2025-07-08", //rok-mesiac-den
|
||||
language: responseSettings[0]["lang"],
|
||||
rvo_name: responseSettings[0]["rvo_name"],
|
||||
project_id: responseSettings[0]["project_id"],
|
||||
rvoTbName: dbs.relaysData[0]["tbname"],
|
||||
temperature_address: responseSettings[0]["temperature_address"],
|
||||
controller_type: responseSettings[0]["controller_type"],
|
||||
serial_port: responseSettings[0]["serial_port"],
|
||||
node_status_nok_time: responseSettings[0]["node_status_nok_time"] * 60 * 60 * 1000,// hour * minutes *
|
||||
latitude: responseSettings[0]["latitude"],
|
||||
longitude: responseSettings[0]["longitude"],
|
||||
no_voltage: new Set(),//modbus_citysys - elektromer
|
||||
backup_on_failure: responseSettings[0]["backup_on_failure"],
|
||||
restore_from_backup: responseSettings[0]["restore_from_backup"],
|
||||
restore_backup_wait: responseSettings[0]["restore_backup_wait"],
|
||||
mqtt_host: responseSettings[0]["mqtt_host"],
|
||||
mqtt_clientid: responseSettings[0]["mqtt_clientid"],
|
||||
mqtt_username: responseSettings[0]["mqtt_username"],
|
||||
mqtt_port: responseSettings[0]["mqtt_port"],
|
||||
phases: responseSettings[0]["phases"],
|
||||
cloud_topic: responseSettings[0]["cloud_topic"],
|
||||
has_main_switch: responseSettings[0]["has_main_switch"],
|
||||
|
||||
dbs.settings = {
|
||||
edge_fw_version : "2025-01-02", //rok-mesiac-den
|
||||
language : responseSettings[0]["lang"],
|
||||
rvo_name : responseSettings[0]["rvo_name"],
|
||||
project_id : responseSettings[0]["project_id"],
|
||||
rvoTbName : dbs.relaysData[0]["tbname"],
|
||||
temperature_address : responseSettings[0]["temperature_address"],
|
||||
controller_type : responseSettings[0]["controller_type"],
|
||||
serial_port : responseSettings[0]["serial_port"],
|
||||
node_status_nok_time : responseSettings[0]["node_status_nok_time"] * 60 * 60 * 1000 ,// hour * minutes *
|
||||
latitude : responseSettings[0]["latitude"],
|
||||
longitude : responseSettings[0]["longitude"],
|
||||
no_voltage : new Set(),//modbus_citysys - elektromer
|
||||
backup_on_failure : responseSettings[0]["backup_on_failure"],
|
||||
restore_from_backup : responseSettings[0]["restore_from_backup"],
|
||||
restore_backup_wait : responseSettings[0]["restore_backup_wait"],
|
||||
mqtt_host : responseSettings[0]["mqtt_host"],
|
||||
mqtt_clientid : responseSettings[0]["mqtt_clientid"],
|
||||
mqtt_username : responseSettings[0]["mqtt_username"],
|
||||
mqtt_port : responseSettings[0]["mqtt_port"],
|
||||
phases: responseSettings[0]["phases"],
|
||||
cloud_topic: responseSettings[0]["cloud_topic"],
|
||||
|
||||
//dynamic values
|
||||
masterNodeIsResponding : true, //cmd_manager
|
||||
maintenance_mode : false,
|
||||
}
|
||||
|
||||
FLOW.dbLoaded = true;
|
||||
initNotification();
|
||||
|
||||
setTimeout(()=> {
|
||||
console.log("DB_INIT - data loaded");
|
||||
instance.send(0, "_")
|
||||
}, 5000)
|
||||
|
||||
};
|
||||
//dynamic values
|
||||
masterNodeIsResponding: true, //cmd_manager
|
||||
maintenance_mode: false,
|
||||
}
|
||||
|
||||
|
||||
let rvo_number = responseSettings[0]["rvo_name"].match(/\D+(\d{1,2})_/)[1];
|
||||
dbs.settings.energy_to_switch_lamps = total_energy[rvo_number];
|
||||
if (dbs.settings.energy_to_switch_lamps === undefined) console.log('=============== db_init.js: energy_to_switch_lamps is undefined');
|
||||
|
||||
FLOW.dbLoaded = true;
|
||||
errorHandler.setProjectId(dbs.settings.project_id);
|
||||
initNotification();
|
||||
|
||||
//APP START - send to data services
|
||||
const toService = {
|
||||
id: dbs.settings.project_id,
|
||||
name: dbs.settings.rvo_name,
|
||||
fw_version: dbs.settings.edge_fw_version,
|
||||
startdate: new Date().toISOString().slice(0, 19).replace('T', ' '),
|
||||
js_error: "",
|
||||
error_message: ""
|
||||
};
|
||||
|
||||
instance.send(SEND_TO.infoSender, toService);
|
||||
console.log("----------------> START - message send to service", toService);
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("DB_INIT - data loaded");
|
||||
instance.send(SEND_TO.db_init, "_")
|
||||
}, 5000)
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -34,32 +34,22 @@ Currently we are interested in pins no. 1,2,3,6,8,9,10,16
|
|||
pins number 11, 12, 13 (we receive 10,11,12 in rsPortReceivedData) are "stykace"
|
||||
When port receives data, it must be exactly 4 bytes long. Second byte is pin, that changed its value, fourth byte is value itself.
|
||||
After that, we set this value to "previousValues[allPins[whichpin]]" variable
|
||||
*/
|
||||
|
||||
state_of_main_switch - reportovat stav hlaveho istica : 0-> off 1-> on
|
||||
rotary_switch_state - sem by sa mal reportovat stav vstupov manual a auto pola nasledovnej logiky: Manual = 1 a Auto = 0 -> Manu
|
||||
Manual = 0 a Auto = 0 -> Off, Manual = 0 a Auto = 1 -> Automatic
|
||||
|
||||
/*
|
||||
RVO objekt:
|
||||
state_of_main_switch - sem sa bude reportovať stav hlavného ističa : 0-> off 1-> on (toto nie je na platforme, ale Rado to už do entity type doplnil)
|
||||
rotary_switch_state - sem by sa mal reportovať stav vstupov manual a auto podľa nasledovnej logiky:
|
||||
Manual = 1 a Auto = 0 -> vyreportuje Manual
|
||||
Manual = 0 a Auto = 0 -> vyreportuje Off
|
||||
Manual = 0 a Auto = 1 -> vyreportuje Automatic
|
||||
door_condition - pin 6, dverový kontakt -> 1 -> vyreportuje Closed, 0 -> vyreportuje Ope
|
||||
twilight_sensor - hodnotu, ktoru vracia ten analogovy vstup (17) treba poslat sem ako float number. Zrejme tu potom pridame nejaky koeficient prevodu na luxy
|
||||
|
||||
door_condition - tuto ide pin 6, dverový kontakt -> 1 -> vyreportuje Closed, 0 -> vyreportuje Open
|
||||
twilight_sensor - hodnotu, ktorú vracia ten analógový vstup (17) treba poslať sem ako float number. Zrejme tu potom pridáme nejaký koeficient prevodu na luxy
|
||||
|
||||
zjavne nám v jsone chýba stav hlavného ističa. Musíme to potom doplniť
|
||||
|
||||
Na každú líniu:
|
||||
state_of_breaker - podľa indexu ističa sa reportuje jeho stav, teda istič 1 na líniu 1: 0-> off 1-> on
|
||||
state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda stykač 1 na líniu 1: 0-> off 1-> on
|
||||
momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale tá zmena by sa mala ukázať aj na platforme
|
||||
Na kazdu liniu
|
||||
state_of_breaker - podla indexu istica sa reportuje jeho stav, teda istic na liniu 1: 0-> off, 1-> on
|
||||
state_of_contactor - podla indexu stkaca sa reportuje jeho stav, teda stykac 1 na liniu 1: 0-> off, 1-> on
|
||||
*/
|
||||
|
||||
const { errLogger, logger, monitor } = require('./helper/logger');
|
||||
const SerialPort = require('serialport');
|
||||
const WebSocket = require('ws');
|
||||
//const { exec } = require('child_process');
|
||||
const { runSyncExec } = require('./helper/serialport_helper');
|
||||
const { bytesToInt, resizeArray } = require('./helper/utils');
|
||||
const { sendNotification } = require('./helper/notification_reporter');
|
||||
|
|
@ -68,8 +58,7 @@ const bitwise = require('bitwise');
|
|||
const DataToTbHandler = require('./helper/DataToTbHandler');
|
||||
let tbHandler;
|
||||
|
||||
const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
|
||||
const errorHandler = new ErrorToServiceHandler();
|
||||
const errorHandler = require('./helper/ErrorToServiceHandler');
|
||||
|
||||
let ws = null;
|
||||
let rsPort = null;
|
||||
|
|
@ -80,6 +69,7 @@ let rvoTbName;
|
|||
let GLOBALS; //FLOW global GLOBALS
|
||||
let SETTINGS; // GLOBALS.settings
|
||||
let controller_type;
|
||||
let hasMainSwitch;
|
||||
|
||||
let alarmStatus = "OFF";
|
||||
|
||||
|
|
@ -107,7 +97,7 @@ exports.install = function(instance) {
|
|||
let previousValues = {};
|
||||
let rsPortReceivedData = [];
|
||||
|
||||
//to be able to get proper twilight values, when
|
||||
//to be able to get proper twilight values
|
||||
let twilight_sensor_interval = 5;//minutes
|
||||
let twilight_sensor = [];
|
||||
const twilight_sensor_array = [];
|
||||
|
|
@ -134,21 +124,22 @@ exports.install = function(instance) {
|
|||
};
|
||||
*/
|
||||
|
||||
//status for calculating Statecodes
|
||||
let deviceStatus = { //key is device name: temperature,....
|
||||
"state_of_main_switch": "Off", //Hlavný istič
|
||||
"rotary_switch_state": "Off", //Prevádzkový mód
|
||||
//status for calculating Statecodes-we make it global to see it from outside
|
||||
FLOW.deviceStatus = { //key is device name: temperature,....
|
||||
"state_of_main_switch": "Off", //Hlavny istic (alebo druhy dverovy kontakt)
|
||||
"rotary_switch_state": "Off", //Prevadzkovy
|
||||
"door_condition": "closed", //Dverový kontakt
|
||||
"em": "OK", //elektromer rvo
|
||||
"temperature": "OK", //templomer
|
||||
"battery": "OK", //Batéria
|
||||
"battery": "OK", //Bateria
|
||||
"power_supply": "OK", //Zdroj
|
||||
"master_node": "OK", //MN - GLOBALS.settings.masterNodeIsResponding
|
||||
"no_voltage": "OK", //GLOBALS.settings.no_voltage - výpadok napätia na fáze
|
||||
"state_of_breaker": {}, //"Off",//Istič
|
||||
"state_of_contactor": {}, //"Off",//Stykač
|
||||
"no_voltage": "OK", //GLOBALS.settings.no_voltage - vypadok napatia na faze
|
||||
"state_of_breaker": {}, //"Off",//Istic
|
||||
"state_of_contactor": {}, //"Off",//Stykac
|
||||
"twilight_sensor": "OK" //lux sensor
|
||||
};
|
||||
let deviceStatus = FLOW.deviceStatus;
|
||||
|
||||
|
||||
function main() {
|
||||
|
|
@ -159,10 +150,12 @@ exports.install = function(instance) {
|
|||
pinsData = GLOBALS.pinsData;
|
||||
relaysData = GLOBALS.relaysData;
|
||||
|
||||
tbHandler = new DataToTbHandler(SEND_TO.tb)
|
||||
tbHandler = new DataToTbHandler(SEND_TO.tb);
|
||||
tbHandler.setSender(exports.title);
|
||||
|
||||
controller_type = SETTINGS.controller_type //"lm" or "unipi" //logicMachine
|
||||
controller_type = SETTINGS.controller_type; //"lm" or "unipi"
|
||||
hasMainSwitch = SETTINGS.has_main_switch;
|
||||
|
||||
if (controller_type == "") controller_type = "lm";
|
||||
|
||||
console.log(exports.title, "controller type: ", controller_type);
|
||||
|
|
@ -201,10 +194,6 @@ exports.install = function(instance) {
|
|||
if (pinsData[key].type == "state_of_contactor") {
|
||||
let pin = key - 1;
|
||||
if (controller_type === "unipi") pin = key;
|
||||
|
||||
//this will modify database
|
||||
let forceTurnOff = true;
|
||||
turnLine("off", line, pin, forceTurnOff, "turn off on startup");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,29 +204,25 @@ exports.install = function(instance) {
|
|||
|
||||
sendTelemetry(values, rvoTbName);
|
||||
|
||||
let time = 5 * 1000;
|
||||
setTimeout(function() {
|
||||
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "buildTasks" });
|
||||
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "buildTasks" });
|
||||
|
||||
sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance);
|
||||
monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
|
||||
}, time);
|
||||
sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance);
|
||||
monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
|
||||
}
|
||||
|
||||
|
||||
function handleRsPort() {
|
||||
|
||||
if (rsPort) {
|
||||
rsPort.removeAllListeners();
|
||||
rsPort = null;
|
||||
}
|
||||
|
||||
//TODO build according to pins!!!
|
||||
//! rsPort to open are the same for lm and unipi and electromer ("/dev/ttymxc0")
|
||||
const setRSPortData = [0xAA, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 1, 1, 1, 1, 0, 0, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0];
|
||||
rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false });
|
||||
|
||||
rsPort.on('error', function(err) {
|
||||
logger.debug("rsPort opened error - failed", err.message);
|
||||
instance.send(SEND_TO.debug, err.message);
|
||||
|
||||
errorHandler.sendMessageToService(exports.title + " rsPort opened error - failed: " + err.message);
|
||||
})
|
||||
|
||||
rsPort.on('open', async function() {
|
||||
|
||||
await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function(status) {
|
||||
|
|
@ -298,8 +283,18 @@ exports.install = function(instance) {
|
|||
|
||||
});
|
||||
|
||||
rsPort.on('error', err => {
|
||||
let message = "Dido: rsPort error: " + err.message;
|
||||
logger.debug(message);
|
||||
monitor.info(message);
|
||||
errorHandler.sendMessageToService(message);
|
||||
})
|
||||
|
||||
rsPort.on("close", () => {
|
||||
rsPort.close();
|
||||
let message = "Dido: rsPort closed - reconnecting ...";
|
||||
logger.debug(message);
|
||||
monitor.info(message);
|
||||
setTimeout(handleRsPort, 1000);
|
||||
})
|
||||
|
||||
rsPort.open();
|
||||
|
|
@ -308,6 +303,11 @@ exports.install = function(instance) {
|
|||
|
||||
function handleWebSocket() {
|
||||
|
||||
if (ws) {
|
||||
ws.removeAllListeners();
|
||||
ws = null;
|
||||
}
|
||||
|
||||
//to keep websocket opened, we send request every 150 seconds
|
||||
let startRequests = null;
|
||||
|
||||
|
|
@ -319,16 +319,12 @@ exports.install = function(instance) {
|
|||
instance.send(0, exports.title + " running");
|
||||
turnAlarm("off");
|
||||
|
||||
// useTurnOffCounter = true;
|
||||
// turnOffCounter = relaysData.length - 1;
|
||||
initialSetting();
|
||||
ws.send(JSON.stringify({ "cmd": "all" }));
|
||||
|
||||
setTimeout(function() { ws.send(JSON.stringify({ cmd: "all" })) }, 5000);
|
||||
// we request dev info about neuron device from evok to keep websocket connection alive
|
||||
// for some reason this request returns no data, but connection keeps alive
|
||||
// https://evok.api-docs.io/1.0/mpqzDwPwirsoq7i5A/websocket
|
||||
startRequests = setInterval(() => {
|
||||
// console.log(" *** data from evok requested");
|
||||
ws.send(JSON.stringify({ "cmd": "filter", "dev": ["neuron"] }));
|
||||
}, 150000)
|
||||
};
|
||||
|
|
@ -375,23 +371,13 @@ exports.install = function(instance) {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
ws.on('error', (err) => {
|
||||
monitor.info('websocket error, reconnect')
|
||||
instance.send(SEND_TO.debug, err.message);
|
||||
clearInterval(startRequests);
|
||||
ws = null;
|
||||
setTimeout(handleWebSocket, 1000);
|
||||
ws.on('error', err => {
|
||||
logger.debug('Dido: websocket error', err);
|
||||
})
|
||||
|
||||
|
||||
ws.onclose = function() {
|
||||
// connection closed, discard old websocket and create a new one in 5s
|
||||
// stopRequests();
|
||||
monitor.info('websocket onclose, reconnect')
|
||||
logger.debug('Dido: websocket onclose, reconnecting...')
|
||||
clearInterval(startRequests);
|
||||
ws = null;
|
||||
console.log("ws is null now, reconnecting...");
|
||||
setTimeout(handleWebSocket, 1000);
|
||||
}
|
||||
}
|
||||
|
|
@ -401,7 +387,6 @@ exports.install = function(instance) {
|
|||
if (ws) ws.close();
|
||||
})
|
||||
|
||||
|
||||
function getPin(line) {
|
||||
//conversionTable
|
||||
let keys = Object.keys(pinsData);
|
||||
|
|
@ -502,14 +487,14 @@ exports.install = function(instance) {
|
|||
if (!force) {
|
||||
if (relaysData[line].contactor == value) {
|
||||
instance.send(SEND_TO.debug, `line is already ${onOrOff} ` + line);
|
||||
logger.debug(`turnLine: line is already ${onOrOff} `, line);
|
||||
logger.debug(`Dido: turnLine: line is already ${onOrOff} `, line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if(!rsPort.isOpen && !ws)
|
||||
if (!rsPort && !ws) {
|
||||
errLogger.error("dido controller - port or websocket is not opened");
|
||||
errLogger.error("Dido - port or websocket is not opened");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -521,21 +506,20 @@ exports.install = function(instance) {
|
|||
|
||||
rsPort.write(Buffer.from(arr), function(err) {
|
||||
if (err === undefined) {
|
||||
monitor.info(`turnLine ${onOrOff} zapisal do rsPort-u`, line, pin, arr, info);
|
||||
monitor.info(`Dido: turnLine ${onOrOff} zapisal do rsPort-u`, line, pin, arr, info);
|
||||
switchLogic(arr);
|
||||
}
|
||||
else {
|
||||
monitor.info(`turnLine ${onOrOff} WRITE error`, err);
|
||||
monitor.info(`Dido: turnLine ${onOrOff} WRITE error`, err);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else if (ws) {
|
||||
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
|
||||
monitor.info(`turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
|
||||
monitor.info(`Dido: turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
|
||||
let cmd = { "cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": value };
|
||||
ws.send(JSON.stringify(cmd));
|
||||
switchLogic(pin, value)
|
||||
}
|
||||
|
||||
//if rvo is 24/7, it has just one switching profile point at 13:00. we do not want to send notification as it repeats every day.
|
||||
|
|
@ -593,10 +577,12 @@ exports.install = function(instance) {
|
|||
})
|
||||
|
||||
|
||||
|
||||
|
||||
// we expect array as flowdata.data
|
||||
instance.on("1", flowdata => {
|
||||
|
||||
console.log(flowdata.data);
|
||||
//console.log(flowdata.data);
|
||||
|
||||
if (!flowdata.data instanceof Object) return;
|
||||
|
||||
|
|
@ -609,17 +595,6 @@ exports.install = function(instance) {
|
|||
else if (obj.command == "off") turnLine("off", line, undefined, force, info);
|
||||
else if (obj.command == "turnOnAlarm") turnAlarm("on");
|
||||
else if (obj.command == "turnOffAlarm") turnAlarm("off");
|
||||
|
||||
//! ake data prichadzaju z cmd_manager.js ???
|
||||
//TODO transform to websocket
|
||||
if (Array.isArray(obj)) {
|
||||
|
||||
rsPort.write(Buffer.from(obj), function(err) {
|
||||
switchLogic(obj);
|
||||
|
||||
instance.send(SEND_TO.debug, { "WRITE": obj });
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -627,27 +602,27 @@ exports.install = function(instance) {
|
|||
|
||||
let bits = [];
|
||||
|
||||
//Hlavný istič - state_of_main_switch => v rvo senica je to druhy door pre silovu cast (EM)
|
||||
if (deviceStatus["state_of_main_switch"] == "closed") {
|
||||
//Hlavny istic - state_of_main_switch => v rvo senica je to druhy door pre silovu cast (EM)
|
||||
if (deviceStatus["state_of_main_switch"] === "closed" || deviceStatus["state_of_main_switch"] === "Off") {
|
||||
bits.push(0);
|
||||
}
|
||||
else {
|
||||
bits.push(1);
|
||||
}
|
||||
|
||||
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
|
||||
//Prevadzkovy mod - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
|
||||
if (!SETTINGS.maintenance_mode) {
|
||||
if (deviceStatus["rotary_switch_state"] == "Manual") {
|
||||
if (deviceStatus["rotary_switch_state"] === "Manual") {
|
||||
bits.push(0);
|
||||
bits.push(1);
|
||||
}
|
||||
|
||||
if (deviceStatus["rotary_switch_state"] == "Automatic") {
|
||||
if (deviceStatus["rotary_switch_state"] === "Automatic") {
|
||||
bits.push(0);
|
||||
bits.push(0);
|
||||
}
|
||||
|
||||
if (deviceStatus["rotary_switch_state"] == "Off") {
|
||||
if (deviceStatus["rotary_switch_state"] === "Off") {
|
||||
bits.push(1);
|
||||
bits.push(0);
|
||||
}
|
||||
|
|
@ -657,8 +632,8 @@ exports.install = function(instance) {
|
|||
bits.push(1);
|
||||
}
|
||||
|
||||
//Dverový kontakt
|
||||
if (deviceStatus["door_condition"] == "closed") {
|
||||
//Dverovy kontakt
|
||||
if (deviceStatus["door_condition"] === "closed") {
|
||||
bits.push(0);
|
||||
}
|
||||
else {
|
||||
|
|
@ -666,7 +641,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//EM
|
||||
if (deviceStatus["em"] == "NOK") {
|
||||
if (deviceStatus["em"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
|
|
@ -674,7 +649,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//Teplomer
|
||||
if (deviceStatus["temperature"] == "NOK") {
|
||||
if (deviceStatus["temperature"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
|
|
@ -682,7 +657,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//Batéria
|
||||
if (deviceStatus["battery"] == "NOK") {
|
||||
if (deviceStatus["battery"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
|
|
@ -690,7 +665,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//Zdroj
|
||||
if (deviceStatus["power_supply"] == "NOK") {
|
||||
if (deviceStatus["power_supply"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
|
|
@ -698,7 +673,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//MN
|
||||
if (deviceStatus["master_node"] == "NOK") {
|
||||
if (deviceStatus["master_node"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
|
|
@ -706,14 +681,14 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//výpadok napätia na fáze
|
||||
if (deviceStatus["no_voltage"] == "NOK") {
|
||||
if (deviceStatus["no_voltage"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
bits.push(0);
|
||||
}
|
||||
|
||||
if (deviceStatus["twilight_sensor"] == "NOK") {
|
||||
if (deviceStatus["twilight_sensor"] === "NOK") {
|
||||
bits.push(1);
|
||||
}
|
||||
else {
|
||||
|
|
@ -769,6 +744,26 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
|
||||
function pinsForRvoStatus(controllerType, hasMainSwitch) {
|
||||
|
||||
let pins = [];
|
||||
|
||||
if (controllerType === "lm") {
|
||||
pins = [1, 4, 6];
|
||||
if (hasMainSwitch === 1) {
|
||||
pins = [4, 6];
|
||||
}
|
||||
} else if (controllerType === "unipi") {
|
||||
pins = ["input1_01", "input1_04", "input1_05"];
|
||||
if (hasMainSwitch === 1) {
|
||||
pins = ["input1_01", "input1_04"];
|
||||
}
|
||||
}
|
||||
|
||||
return pins;
|
||||
}
|
||||
|
||||
|
||||
function checkRvoStatus() {
|
||||
|
||||
// we check if any of these pins values are 0 --> it means status RVO is "NOK"
|
||||
|
|
@ -777,12 +772,12 @@ exports.install = function(instance) {
|
|||
let status = "OK";
|
||||
|
||||
for (const [key, value] of Object.entries(deviceStatus)) {
|
||||
if (["em", "twilight_sensor", "temperature", "master_node"].includes(key) && value == "NOK") status = "NOK";
|
||||
if (["em", "twilight_sensor", "temperature", "master_node"].includes(key) && value === "NOK") status = "NOK";
|
||||
}
|
||||
|
||||
if (status == "OK") {
|
||||
let pinIndexes = [1, 4, 6];
|
||||
if (controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05'];
|
||||
if (status === "OK") {
|
||||
|
||||
let pinIndexes = pinsForRvoStatus(controller_type, hasMainSwitch);
|
||||
|
||||
for (const pinIndex of pinIndexes) {
|
||||
if (previousValues[pinIndex] === 0) {
|
||||
|
|
@ -838,28 +833,20 @@ exports.install = function(instance) {
|
|||
let value = "On";
|
||||
if (newPinValue === 0) value = "Off";
|
||||
|
||||
//Hlavný istič
|
||||
//! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri
|
||||
//! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition'
|
||||
// if(type === "!!!state_of_main_switch")
|
||||
// {
|
||||
// if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
|
||||
// {
|
||||
// sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
|
||||
// values["status"] = "NOK";
|
||||
//Hlavny istic
|
||||
if (type === "state_of_main_switch" && hasMainSwitch) {
|
||||
if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) {
|
||||
sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance, "state_of_main_switch");
|
||||
deviceStatus["state_of_main_switch"] = "Off";
|
||||
}
|
||||
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
|
||||
sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance, "state_of_main_switch");
|
||||
deviceStatus["state_of_main_switch"] = "On";
|
||||
}
|
||||
}
|
||||
|
||||
// deviceStatus["state_of_main_switch"] = "Off";
|
||||
// }
|
||||
// else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
|
||||
// {
|
||||
// sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
|
||||
|
||||
// deviceStatus["state_of_main_switch"] = "On";
|
||||
// }
|
||||
// }
|
||||
|
||||
//Prevádzkový mód
|
||||
if (type == "rotary_switch_state") {
|
||||
//Prevadzkovy mod
|
||||
else if (type == "rotary_switch_state") {
|
||||
// combination of these two pins required to get result
|
||||
let pin2, pin3;
|
||||
if (pinIndex == 2 || pinIndex == "input1_02") {
|
||||
|
|
@ -911,7 +898,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
}
|
||||
|
||||
//Batéria - pin 5
|
||||
//Bateria - pin 5
|
||||
else if (type === "battery") {
|
||||
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
|
||||
sendNotification("switchLogic", rvoTbName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
|
||||
|
|
@ -925,27 +912,30 @@ exports.install = function(instance) {
|
|||
}
|
||||
}
|
||||
|
||||
//Dverový kontakt - pin 6
|
||||
//! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch"
|
||||
//! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition'
|
||||
//Dverovy kontakt - pin 6
|
||||
//! Ak je rvo s dvoma dverovymi kontaktami, ked pride z evoku signal z input1_05, co bol predytm "state_of_main switch" handlujeme ho teraz ako 'door_condition'
|
||||
else if (type == "door_condition" || type === "state_of_main_switch") {
|
||||
newPinValue === 0 ? value = "open" : value = "closed";
|
||||
|
||||
if (value === "open" && SETTINGS.maintenance_mode) {
|
||||
sendNotification("switchLogic", rvoTbName, "door_opened", {}, "", SEND_TO.tb, instance, "rvo_door");
|
||||
let door = "door_main";
|
||||
if (type === "state_of_main_switch") door = "door_em";
|
||||
|
||||
if (value === "open") {
|
||||
if (SETTINGS.maintenance_mode) {
|
||||
sendNotification("switchLogic", rvoTbName, door + "_open", {}, "", SEND_TO.tb, instance, door);
|
||||
} else {
|
||||
sendNotification("switchLogic", rvoTbName, door + "_open_without_permission", {}, "", SEND_TO.tb, instance, door);
|
||||
|
||||
// zapneme sirenu
|
||||
// ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition")
|
||||
if (type === "door_condition") turnAlarm("on");
|
||||
}
|
||||
}
|
||||
|
||||
if (value === "open" && !SETTINGS.maintenance_mode) {
|
||||
sendNotification("switchLogic", rvoTbName, "door_opened_without_permission", {}, "", SEND_TO.tb, instance, "rvo_door");
|
||||
|
||||
// zapneme sirenu
|
||||
// ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition")
|
||||
if (type === "door_condition") turnAlarm("on");
|
||||
}
|
||||
|
||||
if (value === "closed") {
|
||||
if (alarmStatus == "ON") turnAlarm("off");
|
||||
sendNotification("switchLogic", rvoTbName, "door_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
|
||||
sendNotification("switchLogic", rvoTbName, door + "_close", {}, "", SEND_TO.tb, instance, door);
|
||||
}
|
||||
|
||||
deviceStatus[type] = value;
|
||||
|
|
@ -1028,34 +1018,6 @@ exports.install = function(instance) {
|
|||
|
||||
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged });
|
||||
reportLineStatus(line);
|
||||
|
||||
//modify table relays
|
||||
// dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
|
||||
// builder.callback(function(err, response) {
|
||||
// if(!err)
|
||||
// {
|
||||
// let time = 0;
|
||||
// if(value) time = 1000 * 10;//10 sekund
|
||||
|
||||
// let dataChanged = false;
|
||||
// if(relaysData[line].contactor != newPinValue) dataChanged = true;
|
||||
// relaysData[line].contactor = newPinValue; // 0,1
|
||||
|
||||
// //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles
|
||||
// //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
|
||||
// setTimeout(function(){
|
||||
// instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged});
|
||||
// }, time);
|
||||
|
||||
// reportLineStatus(line);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// errLogger.error("modify table relays failed", err);
|
||||
// }
|
||||
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
else if (type === "state_of_breaker") {
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@ class DataToTbHandler {
|
|||
this.index = index;
|
||||
|
||||
// time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
|
||||
this.timeToHoldTbValue = 30*60; //30 minutes
|
||||
|
||||
this.timeToHoldTbValue = 30 * 60; //30 minutes
|
||||
this.previousValues = {};
|
||||
this.debug = false;
|
||||
this.messageCounter = 0;
|
||||
|
||||
this.itIsNodeReadout = false;
|
||||
this.sender = "";
|
||||
|
||||
// if attribute difference is less than limit value, we do not send to tb.
|
||||
|
||||
// if attribute change difference is less than limit value, we do not send to tb.
|
||||
this.attributeChangeLimit = {
|
||||
temperature: 0.5,
|
||||
Phase_1_voltage: 2,
|
||||
|
|
@ -25,11 +24,12 @@ class DataToTbHandler {
|
|||
Phase_2_power: 2,
|
||||
Phase_3_power: 2,
|
||||
total_power: 2,
|
||||
total_energy: 1,
|
||||
Phase_1_pow_factor: 0.1,
|
||||
Phase_2_pow_factor: 0.1,
|
||||
Phase_3_pow_factor: 0.1,
|
||||
power_factor: 0.1,
|
||||
lifetime: 0.5,
|
||||
lifetime: 2,
|
||||
voltage: 2,
|
||||
power: 2,
|
||||
frequency: 3,
|
||||
|
|
@ -39,6 +39,7 @@ class DataToTbHandler {
|
|||
inclination_y: 10,
|
||||
inclination_z: 10
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
dump() {
|
||||
|
|
@ -52,41 +53,43 @@ class DataToTbHandler {
|
|||
}
|
||||
|
||||
isEmptyObject(obj) {
|
||||
for (var name in obj) {
|
||||
for (var _ in obj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
sendToTb(dataToTb, instance) {
|
||||
|
||||
let keys = Object.keys(dataToTb);
|
||||
sendToTb(data, instance) {
|
||||
|
||||
if(keys.length == 0)
|
||||
{
|
||||
if(this.debug) console.log("sendToTb received empty object", dataToTb);
|
||||
//not to modify data object, we do deep copy:
|
||||
let dataCopy = JSON.parse(JSON.stringify(data));
|
||||
|
||||
let keys = Object.keys(dataCopy);
|
||||
|
||||
if (keys.length == 0) {
|
||||
if (this.debug) console.log("sendToTb received empty object", dataCopy);
|
||||
return;
|
||||
}
|
||||
|
||||
let tbname = keys[0];
|
||||
let ts;
|
||||
|
||||
let arrayOfValues = dataToTb[tbname];
|
||||
let arrayOfValues = dataCopy[tbname];
|
||||
let arrayOfValuesToSend = [];
|
||||
|
||||
for(let i = 0; i < arrayOfValues.length; i++)
|
||||
{
|
||||
for (let i = 0; i < arrayOfValues.length; i++) {
|
||||
|
||||
ts = arrayOfValues[i].ts;
|
||||
let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
|
||||
|
||||
if(!this.isEmptyObject(values))
|
||||
{
|
||||
arrayOfValuesToSend.push({ts: ts, values: values});
|
||||
if (!this.isEmptyObject(values)) {
|
||||
arrayOfValuesToSend.push({ ts: ts, values: values });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(arrayOfValuesToSend.length == 0)
|
||||
{
|
||||
if (arrayOfValuesToSend.length == 0) {
|
||||
//if(this.debug) console.log("data not sent - empty array");
|
||||
return;
|
||||
}
|
||||
|
|
@ -94,7 +97,7 @@ class DataToTbHandler {
|
|||
this.messageCounter++;
|
||||
|
||||
let dataToTbModified = {
|
||||
[tbname]: arrayOfValuesToSend
|
||||
[tbname]: arrayOfValuesToSend
|
||||
}
|
||||
|
||||
//console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
|
||||
|
|
@ -102,56 +105,74 @@ class DataToTbHandler {
|
|||
instance.send(this.index, dataToTbModified);
|
||||
}
|
||||
|
||||
|
||||
getDiffTimestamp(key) {
|
||||
//TODO set different value for given key!!!
|
||||
//if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
|
||||
return this.timeToHoldTbValue * 1000;
|
||||
}
|
||||
|
||||
|
||||
prepareValuesForTb(tbname, timestamp, values) {
|
||||
|
||||
let keys = Object.keys(values);
|
||||
if(!this.previousValues.hasOwnProperty(tbname))
|
||||
{
|
||||
|
||||
if (keys.includes("lifetime")) this.itIsNodeReadout = true;
|
||||
|
||||
if (!this.previousValues.hasOwnProperty(tbname)) {
|
||||
this.previousValues[tbname] = {};
|
||||
}
|
||||
|
||||
//if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);
|
||||
|
||||
for(let i = 0; i < keys.length; i++)
|
||||
{
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
|
||||
let key = keys[i];
|
||||
let value = values[key];
|
||||
|
||||
if(!this.previousValues[tbname].hasOwnProperty(key))
|
||||
{
|
||||
this.previousValues[tbname][key] = {ts: timestamp, value: value};
|
||||
if (!this.previousValues[tbname].hasOwnProperty(key)) {
|
||||
this.previousValues[tbname][key] = { ts: timestamp, value: value };
|
||||
continue;
|
||||
}
|
||||
|
||||
// attributeData ==> voltage: {ts:333333, value:5}
|
||||
// attributeData ==> {voltage: {ts:333333, value:5}}
|
||||
let attributeData = this.previousValues[tbname][key];
|
||||
let attributeToChange = false;
|
||||
if(key in this.attributeChangeLimit) attributeToChange = true;
|
||||
if (key in this.attributeChangeLimit) attributeToChange = true;
|
||||
let limit = this.attributeChangeLimit[key];
|
||||
|
||||
if(attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit)
|
||||
{
|
||||
let timestampDiffToRemoveKey;
|
||||
|
||||
//this will ensure "node statecode" will be sent just once an hour
|
||||
if (this.itIsNodeReadout && key === "statecode") {
|
||||
attributeData.value = value;
|
||||
this.itIsNodeReadout = false;
|
||||
timestampDiffToRemoveKey = 1 * 60 * 60 * 1000; // 1 hour
|
||||
}
|
||||
|
||||
if (key === "twilight_sensor" && value > 100) {
|
||||
attributeData.value = value;
|
||||
}
|
||||
|
||||
//if edge, master or node version do not change, send just once a day:
|
||||
if (["edge_fw_version", "master_node_version", "fw_version"].includes(key)) {
|
||||
timestampDiffToRemoveKey = 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
if (attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit) {
|
||||
|
||||
let diff = timestamp - attributeData.ts;
|
||||
let timestampDiffToRemoveKey = this.getDiffTimestamp(key);
|
||||
if(diff > timestampDiffToRemoveKey)
|
||||
{
|
||||
if (!timestampDiffToRemoveKey) timestampDiffToRemoveKey = this.getDiffTimestamp(key);
|
||||
|
||||
if (diff > timestampDiffToRemoveKey) {
|
||||
attributeData.ts = Date.now();
|
||||
//if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
delete values[key];
|
||||
//if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
attributeData.value = value;
|
||||
attributeData.ts = timestamp;
|
||||
}
|
||||
|
|
@ -162,5 +183,5 @@ class DataToTbHandler {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = DataToTbHandler;
|
||||
module.exports = DataToTbHandler;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,126 +1,91 @@
|
|||
const { MD5 } = require('./md5.js');
|
||||
const { networkInterfaces } = require('os');
|
||||
|
||||
class ErrorToServiceHandler
|
||||
{
|
||||
constructor() {
|
||||
class ErrorToServiceHandler {
|
||||
constructor() {
|
||||
this.previousValues = {};
|
||||
|
||||
this.projects_id = undefined;
|
||||
this.project_id = undefined;
|
||||
|
||||
const nets = networkInterfaces();
|
||||
this.ipAddresses = Object.create(null); // Or just '{}', an empty object
|
||||
this.ipAddresses = {};
|
||||
|
||||
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 (!this.ipAddresses[name]) {
|
||||
this.ipAddresses[name] = [];
|
||||
this.ipAddresses[name] = [];
|
||||
}
|
||||
this.ipAddresses[name].push(net.address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.log(this.ipAddresses);
|
||||
|
||||
}
|
||||
|
||||
setProjectsId(projects_id)
|
||||
{
|
||||
this.projects_id = projects_id;
|
||||
setProjectId(project_id) {
|
||||
this.project_id = project_id;
|
||||
}
|
||||
|
||||
processMessage(message, seconds, message_type)
|
||||
{
|
||||
if(message_type == undefined) message_type = "error_message";
|
||||
if(Array.isArray(message)) message = message.join(', ');
|
||||
|
||||
let key = MD5(message);
|
||||
let timestamp = new Date().getTime();
|
||||
|
||||
//keep in memory - default value is 1h
|
||||
if (seconds === undefined) seconds = 60*60;
|
||||
|
||||
if(!this.previousValues.hasOwnProperty(key))
|
||||
{
|
||||
this.previousValues[key] = {ts: timestamp, duration: seconds};
|
||||
}
|
||||
|
||||
let diff = (timestamp - this.previousValues[key].ts);
|
||||
if(diff < this.previousValues[key].duration*1000) return false;
|
||||
|
||||
this.previousValues[key].ts = timestamp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sendMessageToService(message, seconds, message_type)
|
||||
{
|
||||
|
||||
let f = this.processMessage(message, seconds, message_type);
|
||||
if(!f) return;
|
||||
|
||||
/*
|
||||
//-------------
|
||||
if(message_type == undefined) message_type = "error_message";
|
||||
if(Array.isArray(message)) message = message.join(', ');
|
||||
processMessage(message, seconds) {
|
||||
if (Array.isArray(message)) message = message.join(', ');
|
||||
|
||||
let key = MD5(message);
|
||||
let timestamp = new Date().getTime();
|
||||
let ts = Date.now();
|
||||
|
||||
//keep in memory
|
||||
if (seconds === undefined) seconds = 60*60;
|
||||
//keep in memory - default value is 1h
|
||||
if (seconds === undefined) seconds = 60 * 60;
|
||||
|
||||
if(!this.previousValues.hasOwnProperty(key))
|
||||
{
|
||||
this.previousValues[key] = {ts: timestamp, duration: seconds};
|
||||
if (!this.previousValues.hasOwnProperty(key)) {
|
||||
this.previousValues[key] = { ts: ts, duration: seconds };
|
||||
}
|
||||
|
||||
let diff = (timestamp - this.previousValues[key].ts);
|
||||
if(diff < this.previousValues[key].duration*1000) return;
|
||||
let diff = (ts - this.previousValues[key].ts);
|
||||
if (diff < this.previousValues[key].duration * 1000) return false;
|
||||
|
||||
this.previousValues[key].ts = timestamp;
|
||||
*/
|
||||
this.previousValues[key].ts = ts;
|
||||
|
||||
//-------------------------
|
||||
return message;
|
||||
}
|
||||
|
||||
//send to service
|
||||
|
||||
let dataToInfoSender = {id: this.projects_id};
|
||||
sendMessageToService(message, seconds, message_type) {
|
||||
|
||||
// if error occures too early FLOW.GLOBALS.settings.project_id is still undefined
|
||||
if (this.project_id === undefined) {
|
||||
console.log("ErrorToServiceHandler.js: no project_id");
|
||||
return;
|
||||
}
|
||||
|
||||
let f = this.processMessage(message, seconds);
|
||||
if (f === false) return;
|
||||
|
||||
if (message_type === undefined) message_type = "error_message";
|
||||
|
||||
let toService = {
|
||||
id: this.project_id,
|
||||
ipAddresses: this.ipAddresses
|
||||
};
|
||||
|
||||
//js_error || error_message
|
||||
dataToInfoSender[message_type] = message;
|
||||
dataToInfoSender.ipAddresses = this.ipAddresses;
|
||||
toService[message_type] = message;
|
||||
|
||||
console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender);
|
||||
|
||||
//TODO UGLY!!!
|
||||
// if error occures too early FLOW.GLOBALs.settings.project_id is still undefined
|
||||
// if(this.projects_id === undefined) this.projects_id = FLOW.GLOBALS.settings.project_id;
|
||||
if(this.projects_id === undefined) return;
|
||||
|
||||
/*
|
||||
if(this.projects_id === undefined)
|
||||
{
|
||||
console.log("this.projects_id is undefined");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
console.log("ErrorToServiceHandler------------------------>send to service", toService);
|
||||
|
||||
RESTBuilder.make(function(builder) {
|
||||
builder.method('POST');
|
||||
builder.post(dataToInfoSender);
|
||||
builder.url('http://192.168.252.2:8004/sentmessage');
|
||||
|
||||
builder.callback(function(err, response, output) {
|
||||
console.log("process.on error send", err, response, output, dataToInfoSender);
|
||||
});
|
||||
builder.method('POST');
|
||||
builder.post(toService);
|
||||
builder.url('http://192.168.252.2:8004/sentmessage');
|
||||
|
||||
builder.callback(function(err, response, output) {
|
||||
console.log("process.on error send", err, response, output, toService);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ErrorToServiceHandler;
|
||||
const errorHandler = new ErrorToServiceHandler();
|
||||
|
||||
|
||||
module.exports = errorHandler;
|
||||
//module.exports = ErrorToServiceHandler;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
//key is device, value = str
|
||||
let sentValues= {};
|
||||
//key is device, value = message {}
|
||||
let sentValues = {};
|
||||
let notificationsData = null;
|
||||
let rvoName;
|
||||
|
||||
//sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: node }, "", SEND_TO.tb, instance);
|
||||
|
||||
let ERRWEIGHT = {
|
||||
EMERGENCY: "emergency", // System unusable
|
||||
|
|
@ -23,82 +26,67 @@ var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]);
|
|||
|
||||
function initNotification() {
|
||||
notificationsData = FLOW.GLOBALS.notificationsData;
|
||||
rvoName = FLOW.GLOBALS.settings.rvo_name;
|
||||
}
|
||||
|
||||
|
||||
function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) {
|
||||
|
||||
// return;
|
||||
|
||||
let storeToSendValues = true;
|
||||
if(saveKey == undefined) storeToSendValues = false;
|
||||
if (saveKey == undefined) storeToSendValues = false;
|
||||
|
||||
let lang = FLOW.GLOBALS.settings.language;
|
||||
if(lang != "en" || lang != "sk") lang = "en";
|
||||
|
||||
let tpl = key;
|
||||
let weight = "";
|
||||
let message = {};
|
||||
|
||||
if(notificationsData[key])
|
||||
{
|
||||
weight = notificationsData[key].weight;
|
||||
weight = weight.toLowerCase();
|
||||
let notification = notificationsData[key];
|
||||
|
||||
tpl = notificationsData[key][lang];
|
||||
tpl = template(tpl, params);
|
||||
if (notification) {
|
||||
weight = notification.weight.toLowerCase();
|
||||
|
||||
Object.keys(notification).forEach(item => {
|
||||
if (["en", "sk", "de", "cz", "it", "es"].includes(item)) {
|
||||
message[item] = rvoName + ": " + template(notification[item], params);
|
||||
}
|
||||
})
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
//console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
|
||||
console.error("sendNotification: Notifications: undefined key", key, func );
|
||||
console.error("sendNotification: Notifications: undefined key", key, func);
|
||||
return false;
|
||||
}
|
||||
|
||||
//detect invalid err weight
|
||||
if(getKey(ERRWEIGHT, weight) == undefined)
|
||||
{
|
||||
if (getKey(ERRWEIGHT, weight) == undefined) {
|
||||
console.error("sendNotification: Notifications: undefined weight", weight, key, func);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sentValues.hasOwnProperty(saveKey))
|
||||
{
|
||||
if(sentValues[saveKey] == tpl)
|
||||
{
|
||||
if (sentValues.hasOwnProperty(saveKey)) {
|
||||
if (JSON.stringify(sentValues[saveKey]) == JSON.stringify(message)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(sentValues[saveKey] == undefined)
|
||||
{
|
||||
if(storeToSendValues)
|
||||
{
|
||||
if (sentValues[saveKey] == undefined) {
|
||||
if (storeToSendValues) {
|
||||
//do not send - flow is was started
|
||||
sentValues[saveKey] = tpl;
|
||||
sentValues[saveKey] = message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(saveKey == "rvo_door")
|
||||
{
|
||||
//console.log("******", saveKey, sentValues[saveKey], tpl);
|
||||
}
|
||||
|
||||
if(storeToSendValues) sentValues[saveKey] = tpl;
|
||||
|
||||
let str = FLOW.GLOBALS.settings.rvo_name;
|
||||
if(str != "") str = str + ": ";
|
||||
str = str + tpl;
|
||||
if (storeToSendValues) sentValues[saveKey] = message;
|
||||
|
||||
let content = {
|
||||
"type": weight,
|
||||
"status": "new",
|
||||
"source": {
|
||||
"func":func,
|
||||
"component":instance.id,
|
||||
"component_name":instance.name,
|
||||
"edge":device
|
||||
"func": func,
|
||||
"component": instance.id,
|
||||
"component_name": instance.name,
|
||||
"edge": device
|
||||
},
|
||||
"message":str,
|
||||
"message": message,
|
||||
"message_data": extra
|
||||
};
|
||||
|
||||
|
|
@ -107,7 +95,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
|
|||
{
|
||||
"ts": Date.now(),
|
||||
"values": {
|
||||
"_event":content
|
||||
"_event": content
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
@ -118,6 +106,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
|
|||
} else {
|
||||
bufferError(msg);
|
||||
}*/
|
||||
|
||||
instance.send(tb_output, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
|
||||
|
||||
return true;
|
||||
|
|
@ -129,3 +118,4 @@ module.exports = {
|
|||
ERRWEIGHT,
|
||||
initNotification
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const { exec } = require('child_process');
|
||||
|
||||
function openPort(port){
|
||||
function openPort(port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
var callbackError = function(err) {
|
||||
|
|
@ -25,24 +25,24 @@ function openPort(port){
|
|||
})
|
||||
}
|
||||
|
||||
function runSyncExec(command){
|
||||
function runSyncExec(command) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if(error == null) resolve(stdout);
|
||||
if (error == null) resolve(stdout);
|
||||
reject(error);
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
async function writeData(port, data, readbytes, timeout){
|
||||
async function writeData(port, data, readbytes, timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
// If first item in data array is 255, we just write broadcast command to rsPort
|
||||
// We wait 3 seconds and resolve(["broadcast"])
|
||||
// It is important to resolve with array
|
||||
if(data[0] == 255) {
|
||||
if (data[0] == 255) {
|
||||
|
||||
port.write(Buffer.from(data), function(err) {
|
||||
if (err) {
|
||||
|
|
@ -55,13 +55,12 @@ async function writeData(port, data, readbytes, timeout){
|
|||
}
|
||||
|
||||
//cmd-manager mame http route POST / terminal a tomu sa tiez nastavuje timeout!!!
|
||||
|
||||
|
||||
var callback = function(data) {
|
||||
rsPortReceivedData.push(...data);
|
||||
let l = rsPortReceivedData.length;
|
||||
|
||||
if(l >= readbytes)
|
||||
{
|
||||
if (l >= readbytes) {
|
||||
port.removeListener('data', callback);
|
||||
|
||||
clearTimeout(t);
|
||||
|
|
@ -74,7 +73,7 @@ async function writeData(port, data, readbytes, timeout){
|
|||
let t = setTimeout(() => {
|
||||
port.removeListener('data', callback);
|
||||
|
||||
console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
|
||||
//console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
|
||||
|
||||
reject("TIMEOUT READING");
|
||||
}, timeout);
|
||||
|
|
|
|||
|
|
@ -1,124 +1,112 @@
|
|||
function bytesToInt(bytes, numberOfBytes)
|
||||
{
|
||||
let buffer = [];
|
||||
if(Array.isArray(bytes))
|
||||
{
|
||||
buffer = bytes.slice(0);
|
||||
if(numberOfBytes != undefined)
|
||||
{
|
||||
buffer = bytes.slice(bytes.length - numberOfBytes);
|
||||
}
|
||||
}
|
||||
else buffer.push(bytes);
|
||||
|
||||
//var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
|
||||
let l = (buffer.length - 1) * 8;
|
||||
|
||||
let decimal = 0;
|
||||
for(let i = 0; i < buffer.length; i++)
|
||||
{
|
||||
var s = buffer[i] << l;
|
||||
if(l < 8) s = buffer[i]
|
||||
decimal = decimal + s;
|
||||
|
||||
l = l - 8;
|
||||
|
||||
}
|
||||
|
||||
return decimal;
|
||||
}
|
||||
|
||||
function resizeArray(arr, newSize, defaultValue) {
|
||||
while(newSize > arr.length)
|
||||
arr.push(defaultValue);
|
||||
arr.length = newSize;
|
||||
}
|
||||
|
||||
longToByteArray = function(/*long*/long) {
|
||||
// we want to represent the input as a 8-bytes array
|
||||
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
for ( var index = 0; index < byteArray.length; index ++ ) {
|
||||
var byte = long & 0xff;
|
||||
byteArray [ index ] = byte;
|
||||
long = (long - byte) / 256 ;
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
};
|
||||
|
||||
function addDays(date, days) {
|
||||
var result = new Date(date);
|
||||
result.setDate(result.getDate() + days);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
sleep(2000).then(() => {
|
||||
// Do something after the sleep!
|
||||
|
||||
|
||||
});
|
||||
*/
|
||||
|
||||
function sleep (time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
function isEmptyObject( obj ) {
|
||||
for ( var name in obj ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function convertUTCDateToLocalDate(date) {
|
||||
var newDate = new Date(date);
|
||||
newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
|
||||
return newDate;
|
||||
}
|
||||
|
||||
function addZeroBefore(n) {
|
||||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
var convertBase = function () {
|
||||
|
||||
function convertBase(baseFrom, baseTo) {
|
||||
return function (num) {
|
||||
return parseInt(num, baseFrom).toString(baseTo);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// binary to decimal
|
||||
convertBase.bin2dec = convertBase(2, 10);
|
||||
|
||||
// binary to hexadecimal
|
||||
convertBase.bin2hex = convertBase(2, 16);
|
||||
|
||||
// decimal to binary
|
||||
convertBase.dec2bin = convertBase(10, 2);
|
||||
|
||||
// decimal to hexadecimal
|
||||
convertBase.dec2hex = convertBase(10, 16);
|
||||
|
||||
// hexadecimal to binary
|
||||
convertBase.hex2bin = convertBase(16, 2);
|
||||
|
||||
// hexadecimal to decimal
|
||||
convertBase.hex2dec = convertBase(16, 10);
|
||||
|
||||
return convertBase;
|
||||
}();
|
||||
|
||||
module.exports = {
|
||||
bytesToInt,
|
||||
longToByteArray,
|
||||
addDays,
|
||||
addZeroBefore,
|
||||
resizeArray,
|
||||
isEmptyObject,
|
||||
sleep,
|
||||
convertUTCDateToLocalDate
|
||||
}
|
||||
function bytesToInt(bytes, numberOfBytes) {
|
||||
let buffer = [];
|
||||
if (Array.isArray(bytes)) {
|
||||
buffer = bytes.slice(0);
|
||||
if (numberOfBytes != undefined) {
|
||||
buffer = bytes.slice(bytes.length - numberOfBytes);
|
||||
}
|
||||
}
|
||||
else buffer.push(bytes);
|
||||
|
||||
let result = 0;
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
result = (result << 8) | buffer[i];
|
||||
}
|
||||
|
||||
return result >>> 0; //ensure it's an unsigned 32-bit number
|
||||
}
|
||||
|
||||
function resizeArray(arr, newSize, defaultValue) {
|
||||
while (newSize > arr.length)
|
||||
arr.push(defaultValue);
|
||||
arr.length = newSize;
|
||||
}
|
||||
|
||||
longToByteArray = function(/*long*/long) {
|
||||
// we want to represent the input as a 8-bytes array
|
||||
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
for (var index = 0; index < byteArray.length; index++) {
|
||||
var byte = long & 0xff;
|
||||
byteArray[index] = byte;
|
||||
long = (long - byte) / 256;
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
};
|
||||
|
||||
function addDays(date, days) {
|
||||
var result = new Date(date);
|
||||
result.setDate(result.getDate() + days);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
sleep(2000).then(() => {
|
||||
// Do something after the sleep!
|
||||
|
||||
|
||||
});
|
||||
*/
|
||||
|
||||
function sleep(time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
function isEmptyObject(obj) {
|
||||
for (var name in obj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function convertUTCDateToLocalDate(date) {
|
||||
var newDate = new Date(date);
|
||||
newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
|
||||
return newDate;
|
||||
}
|
||||
|
||||
function addZeroBefore(n) {
|
||||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
var convertBase = function() {
|
||||
|
||||
function convertBase(baseFrom, baseTo) {
|
||||
return function(num) {
|
||||
return parseInt(num, baseFrom).toString(baseTo);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// binary to decimal
|
||||
convertBase.bin2dec = convertBase(2, 10);
|
||||
|
||||
// binary to hexadecimal
|
||||
convertBase.bin2hex = convertBase(2, 16);
|
||||
|
||||
// decimal to binary
|
||||
convertBase.dec2bin = convertBase(10, 2);
|
||||
|
||||
// decimal to hexadecimal
|
||||
convertBase.dec2hex = convertBase(10, 16);
|
||||
|
||||
// hexadecimal to binary
|
||||
convertBase.hex2bin = convertBase(16, 2);
|
||||
|
||||
// hexadecimal to decimal
|
||||
convertBase.hex2dec = convertBase(16, 10);
|
||||
|
||||
return convertBase;
|
||||
}();
|
||||
|
||||
module.exports = {
|
||||
bytesToInt,
|
||||
longToByteArray,
|
||||
addDays,
|
||||
addZeroBefore,
|
||||
resizeArray,
|
||||
isEmptyObject,
|
||||
sleep,
|
||||
convertUTCDateToLocalDate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,69 +33,49 @@ exports.install = function(instance) {
|
|||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function sendValues()
|
||||
{
|
||||
if(!configured) return;
|
||||
|
||||
if(Object.keys(allValues).length > 0)
|
||||
{
|
||||
if(id)
|
||||
{
|
||||
delete allValues.__force__;
|
||||
let dataToSend = {...allValues};
|
||||
dataToSend.id = id;
|
||||
dataToSend.ipAddresses = ipAddresses;
|
||||
|
||||
instance.send(0, dataToSend);
|
||||
|
||||
allValues = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(exports.title, "unable to send data, no id");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function sendValues() {
|
||||
if (!configured) return;
|
||||
|
||||
if (Object.keys(allValues).length > 0) {
|
||||
let dataToSend = { ...allValues };
|
||||
dataToSend.id = id;
|
||||
dataToSend.ipAddresses = ipAddresses;
|
||||
|
||||
instance.send(0, dataToSend);
|
||||
|
||||
allValues = {};
|
||||
}
|
||||
}
|
||||
|
||||
instance.on("close", () => {
|
||||
clearInterval(sendAllValuesInterval);
|
||||
})
|
||||
|
||||
instance.on("0", _ => {
|
||||
id = FLOW.GLOBALS.settings.project_id;
|
||||
configured = true;
|
||||
if (id) configured = true;
|
||||
else console.log(exports.title, "InfoSender: Unable to send data, no id");
|
||||
})
|
||||
|
||||
instance.on("1", flowdata => {
|
||||
|
||||
allValues = { ...allValues, ...flowdata.data};
|
||||
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);
|
||||
|
||||
}, 60000 * 3);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,12 +36,13 @@ let mainSocket;
|
|||
let phases;
|
||||
//phases where voltage is 0 (set)
|
||||
let noVoltage;
|
||||
let energyToSwitchLamps;
|
||||
|
||||
exports.install = function(instance) {
|
||||
|
||||
class SocketWithClients {
|
||||
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.stream = null;
|
||||
this.socket = null;
|
||||
this.clients = {};
|
||||
|
|
@ -55,7 +56,7 @@ exports.install = function(instance) {
|
|||
this.indexInDeviceConfig = 0; // first item in deviceConfig
|
||||
this.lengthOfActualDeviceStream = null;
|
||||
this.device = null;
|
||||
|
||||
|
||||
// lampSwitchNotification helper variables
|
||||
this.onNotificationSent = false;
|
||||
this.offNotificationSent = false;
|
||||
|
|
@ -66,7 +67,7 @@ exports.install = function(instance) {
|
|||
|
||||
buildPhases = () => {
|
||||
let a = [];
|
||||
for (let i = 1; i<= phases; i++) {
|
||||
for (let i = 1; i <= phases; i++) {
|
||||
a.push(`Phase_${i}_voltage`)
|
||||
}
|
||||
return a;
|
||||
|
|
@ -76,30 +77,30 @@ exports.install = function(instance) {
|
|||
|
||||
let obj = this;
|
||||
|
||||
if (this.socket) {
|
||||
this.socket.removeAllListeners();
|
||||
this.socket = null;
|
||||
}
|
||||
|
||||
this.socket = new SerialPort("/dev/ttymxc0", {
|
||||
baudRate: 9600,
|
||||
})
|
||||
|
||||
// we create a client for every deviceAddress ( = address) in list and push them into dictionary
|
||||
for( let i = 0; i < deviceConfig.length; i++)
|
||||
{
|
||||
for (let i = 0; i < deviceConfig.length; i++) {
|
||||
this.clients[deviceConfig[i].deviceAddress] = new modbus.client.RTU(this.socket, deviceConfig[i].deviceAddress, 2000); // 2000 is timeout in register request, default is 5000, which is too long
|
||||
}
|
||||
|
||||
this.socket.on('error', function(e) {
|
||||
console.log('socket connection error', e);
|
||||
if(e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') {
|
||||
console.log(exports.title + ' Waiting 10 seconds before trying to connect again');
|
||||
setTimeout(obj.startSocket, 10000);
|
||||
}
|
||||
console.log('Modbus_reader: Socket connection error', e); //'ECONNREFUSED' or 'ECONNRESET' ??
|
||||
});
|
||||
|
||||
this.socket.on('close', function() {
|
||||
console.log('Socket connection closed ' + exports.title + ' Waiting 10 seconds before trying to connect again');
|
||||
console.log('Modbus_reader: Socket connection closed - Waiting 10 seconds before connecting again');
|
||||
setTimeout(obj.startSocket, 10000);
|
||||
});
|
||||
|
||||
this.socket.on('open', function () {
|
||||
this.socket.on('open', function() {
|
||||
console.log("socket connected");
|
||||
obj.getActualStreamAndDevice();
|
||||
obj.timeoutInterval = timeoutInterval - DELAY_BETWEEN_DEVICES; // to make sure readout always runs in timeoutinterval we substract DELAY_BETWEEN_DEVICES
|
||||
|
|
@ -112,11 +113,12 @@ exports.install = function(instance) {
|
|||
this.index = 0;
|
||||
this.errors = 0;
|
||||
this.stream = dev.stream;
|
||||
this.lengthOfActualDeviceStream = dev.stream.length;
|
||||
this.lengthOfActualDeviceStream = dev.stream.length;
|
||||
this.deviceAddress = dev.deviceAddress; // 1 or 2 or any number
|
||||
this.device = dev.device; //em340, twilight_sensor
|
||||
|
||||
if(this.indexInDeviceConfig == 0) setTimeout(this.readRegisters, this.timeoutInterval);
|
||||
//if we just start to loop devices from the beginning, or there is just 1 device in config, we wait whole timeoutInterval
|
||||
if (this.indexInDeviceConfig == 0 || deviceConfig.length === 1) setTimeout(this.readRegisters, this.timeoutInterval);
|
||||
else setTimeout(this.readRegisters, DELAY_BETWEEN_DEVICES);
|
||||
}
|
||||
|
||||
|
|
@ -130,21 +132,18 @@ exports.install = function(instance) {
|
|||
let obj = this;
|
||||
|
||||
this.clients[this.deviceAddress].readHoldingRegisters(register, size)
|
||||
.then( function (resp) {
|
||||
|
||||
.then(function(resp) {
|
||||
|
||||
resp = resp.response._body.valuesAsArray; //resp is array of length 1 or 2, f.e. [2360,0]
|
||||
// console.log(deviceAddress, register, tbAttribute, resp);
|
||||
|
||||
//device is responding again after NOK status
|
||||
if(numberOfNotResponding.hasOwnProperty(obj.device))
|
||||
{
|
||||
if (numberOfNotResponding.hasOwnProperty(obj.device)) {
|
||||
let message = "";
|
||||
if(obj.device == "em340")
|
||||
{
|
||||
if (obj.device == "em340") {
|
||||
message = "electrometer_ok";
|
||||
}
|
||||
else if(obj.device == "twilight_sensor")
|
||||
{
|
||||
else if (obj.device == "twilight_sensor") {
|
||||
message = "twilight_sensor_ok";
|
||||
}
|
||||
message && sendNotification("modbus_reader: readRegisters", tbName, message, {}, "", SEND_TO.tb, instance);
|
||||
|
|
@ -157,25 +156,21 @@ exports.install = function(instance) {
|
|||
obj.index++;
|
||||
obj.readAnotherRegister();
|
||||
|
||||
}).catch (function () {
|
||||
}).catch(function() {
|
||||
|
||||
//console.log("errors pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute);
|
||||
|
||||
|
||||
obj.errors++;
|
||||
if(obj.errors == obj.lengthOfActualDeviceStream)
|
||||
{
|
||||
instance.send(SEND_TO.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer
|
||||
|
||||
if (obj.errors == obj.lengthOfActualDeviceStream) {
|
||||
instance.send(SEND_TO.dido_controller, { status: "NOK-" + obj.device }); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer
|
||||
|
||||
//todo - neposlalo notification, ked sme vypojili twilight a neposle to do tb, ale do dido ??
|
||||
if(!numberOfNotResponding.hasOwnProperty(obj.device))
|
||||
{
|
||||
if (!numberOfNotResponding.hasOwnProperty(obj.device)) {
|
||||
let message = "";
|
||||
if(obj.device == "twilight_sensor")
|
||||
{
|
||||
if (obj.device == "twilight_sensor") {
|
||||
message = "twilight_sensor_nok";
|
||||
}
|
||||
else if(obj.device == "em340")
|
||||
{
|
||||
else if (obj.device == "em340") {
|
||||
message = "electrometer_nok";
|
||||
}
|
||||
message && sendNotification("modbus_reader: readingTimeouted", tbName, message, {}, "", SEND_TO.tb, instance);
|
||||
|
|
@ -183,7 +178,7 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
obj.errors = 0;
|
||||
numberOfNotResponding[obj.device] += 1;
|
||||
numberOfNotResponding[obj.device] += 1;
|
||||
}
|
||||
|
||||
// console.error(require('util').inspect(arguments, {
|
||||
|
|
@ -191,9 +186,8 @@ exports.install = function(instance) {
|
|||
// }))
|
||||
|
||||
// if reading out of device's last register returns error, we send accumulated allValues to dido_controller (if allValues are not an empty object)
|
||||
if(obj.index + 1 >= obj.lengthOfActualDeviceStream)
|
||||
{
|
||||
if(!isObjectEmpty(obj.allValues)) instance.send(SEND_TO.dido_controller, {values: obj.allValues});
|
||||
if (obj.index + 1 >= obj.lengthOfActualDeviceStream) {
|
||||
if (!isObjectEmpty(obj.allValues)) instance.send(SEND_TO.dido_controller, { values: obj.allValues });
|
||||
obj.allValues = {};
|
||||
}
|
||||
obj.index++;
|
||||
|
|
@ -203,7 +197,7 @@ exports.install = function(instance) {
|
|||
};
|
||||
|
||||
readAnotherRegister = () => {
|
||||
if(this.index < this.lengthOfActualDeviceStream) setTimeout(this.readRegisters, 0);
|
||||
if (this.index < this.lengthOfActualDeviceStream) setTimeout(this.readRegisters, 0);
|
||||
else this.setNewStream();
|
||||
}
|
||||
|
||||
|
|
@ -212,18 +206,16 @@ exports.install = function(instance) {
|
|||
for (let i = 0; i < this.lengthOfActualDeviceStream; i++) {
|
||||
|
||||
let a = this.stream[i];
|
||||
if (a.register === register)
|
||||
{
|
||||
if (a.register === register) {
|
||||
let tbAttribute = a.tbAttribute;
|
||||
let multiplier = a.multiplier;
|
||||
|
||||
let value = this.calculateValue(response, multiplier);
|
||||
|
||||
let value = this.calculateValue(response, multiplier);
|
||||
// console.log(register, tbName, tbAttribute, response, a.multiplier, value);
|
||||
|
||||
// if(tbName == undefined) return;
|
||||
|
||||
if(this.index + 1 < this.lengthOfActualDeviceStream)
|
||||
{
|
||||
if (this.index + 1 < this.lengthOfActualDeviceStream) {
|
||||
this.allValues[tbAttribute] = value;
|
||||
return;
|
||||
}
|
||||
|
|
@ -236,52 +228,45 @@ exports.install = function(instance) {
|
|||
this.checkNullVoltage(values);
|
||||
this.lampSwitchNotification(values);
|
||||
|
||||
instance.send(SEND_TO.dido_controller, {values: values});
|
||||
instance.send(SEND_TO.dido_controller, { values: values });
|
||||
|
||||
this.allValues = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setNewStream = () =>
|
||||
{
|
||||
if(this.lengthOfActualDeviceStream == this.index)
|
||||
{
|
||||
if(this.indexInDeviceConfig + 1 == deviceConfig.length)
|
||||
{
|
||||
setNewStream = () => {
|
||||
if (this.lengthOfActualDeviceStream == this.index) {
|
||||
if (this.indexInDeviceConfig + 1 == deviceConfig.length) {
|
||||
this.indexInDeviceConfig = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else {
|
||||
this.indexInDeviceConfig += 1;
|
||||
}
|
||||
|
||||
this.getActualStreamAndDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calculateValue = (response, multiplier) =>
|
||||
{
|
||||
calculateValue = (response, multiplier) => {
|
||||
let value = 0;
|
||||
|
||||
let l = response.length;
|
||||
if (l === 2)
|
||||
{
|
||||
value = (response[1]*(2**16) + response[0]);
|
||||
if (l === 2) {
|
||||
value = (response[1] * (2 ** 16) + response[0]);
|
||||
|
||||
if(value >= (2**31)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x80000000), ak vieš robiť logický súčin
|
||||
{
|
||||
value = value - "0xFFFFFFFF" + 1;
|
||||
}
|
||||
if (value >= (2 ** 31)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x80000000), ak vieš robiť logický súčin
|
||||
{
|
||||
value = value - "0xFFFFFFFF" + 1;
|
||||
}
|
||||
}
|
||||
else if (l === 1)
|
||||
{
|
||||
else if (l === 1) {
|
||||
value = response[0];
|
||||
|
||||
if(value >= (2**15)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x8000), ak vieš robiť logický súčin
|
||||
if (value >= (2 ** 15)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x8000), ak vieš robiť logický súčin
|
||||
{
|
||||
value = value - "0xFFFF" + 1;
|
||||
value = value - "0xFFFF" + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -290,59 +275,51 @@ exports.install = function(instance) {
|
|||
|
||||
checkNullVoltage = (values) => {
|
||||
|
||||
if(!(values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_2_voltage") || values.hasOwnProperty("Phase_3_voltage"))) return;
|
||||
if (!(values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_2_voltage") || values.hasOwnProperty("Phase_3_voltage"))) return;
|
||||
|
||||
Object.keys(values).map(singleValue => {
|
||||
if (this.phases.includes(singleValue))
|
||||
{
|
||||
if (this.phases.includes(singleValue)) {
|
||||
let l = singleValue.split("_");
|
||||
let phase = parseInt(l[1]);
|
||||
|
||||
// console.log(values[singleValue], tbName);
|
||||
|
||||
if(values[singleValue] == 0)
|
||||
{
|
||||
if (values[singleValue] == 0) {
|
||||
noVoltage.add(phase);
|
||||
sendNotification("modbus_reader: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase );
|
||||
sendNotification("modbus_reader: checkNullVoltage", tbName, "no_voltage_on_phase", { phase: phase }, "", SEND_TO.tb, instance, "voltage" + phase);
|
||||
// console.log('no voltage')
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
noVoltage.delete(phase);
|
||||
// console.log('voltage detected')
|
||||
sendNotification("modbus_reader: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase);
|
||||
sendNotification("modbus_reader: checkNullVoltage", tbName, "voltage_on_phase_restored", { phase: phase }, "", SEND_TO.tb, instance, "voltage" + phase);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* function sends notification to slack and to tb, if EM total_power value changes more than numberOfNodes*15. This should show, that RVO lamps has been switched on or off
|
||||
*/
|
||||
*/
|
||||
lampSwitchNotification = (values) => {
|
||||
|
||||
if(!values.hasOwnProperty("total_power")) return;
|
||||
if (!values.hasOwnProperty("total_power")) return;
|
||||
|
||||
const actualTotalPower = values.total_power;
|
||||
|
||||
const numberOfNodes = Object.keys(FLOW.GLOBALS.nodesData).length;
|
||||
if(numberOfNodes == 0) numberOfNodes = 20; // to make sure, we send notification if totalPower is more than 300
|
||||
|
||||
if(actualTotalPower > numberOfNodes * 15 && this.onNotificationSent == false)
|
||||
{
|
||||
|
||||
if (actualTotalPower > energyToSwitchLamps && this.onNotificationSent == false) {
|
||||
sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_on", {}, "", SEND_TO.tb, instance);
|
||||
this.onNotificationSent = true;
|
||||
this.offNotificationSent = false;
|
||||
}
|
||||
else if(actualTotalPower <= numberOfNodes * 15 && this.offNotificationSent == false)
|
||||
{
|
||||
}
|
||||
else if (actualTotalPower <= energyToSwitchLamps && this.offNotificationSent == false) {
|
||||
sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_off", {}, "", SEND_TO.tb, instance);
|
||||
this.onNotificationSent = false;
|
||||
this.offNotificationSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const isObjectEmpty = (objectName) => {
|
||||
return Object.keys(objectName).length === 0 && objectName.constructor === Object;
|
||||
|
|
@ -353,7 +330,9 @@ exports.install = function(instance) {
|
|||
phases = FLOW.GLOBALS.settings.phases;
|
||||
tbName = FLOW.GLOBALS.settings.rvoTbName;
|
||||
noVoltage = FLOW.GLOBALS.settings.no_voltage;
|
||||
mainSocket = new SocketWithClients();
|
||||
energyToSwitchLamps = FLOW.GLOBALS.settings.energy_to_switch_lamps / 2.5; //half value is enought to show if lamps are turned on or off
|
||||
if (deviceConfig.length) mainSocket = new SocketWithClients();
|
||||
else console.log("Modbus_reader: no modbus device in configuration");
|
||||
|
||||
// this notification is to show, that flow (unipi) has been restarted
|
||||
sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ exports.group = 'Worksys';
|
|||
exports.color = '#888600';
|
||||
exports.version = '1.0.2';
|
||||
exports.icon = 'sign-out';
|
||||
exports.input = 7;
|
||||
exports.input = 8;
|
||||
exports.output = 1;
|
||||
|
||||
const { exec } = require('child_process');
|
||||
|
|
@ -24,25 +24,27 @@ exports.install = function(instance) {
|
|||
instance.send(0, FLOW.GLOBALS.pinsData);
|
||||
})
|
||||
instance.on("4", _ => {
|
||||
instance.send(0, {rpcSwitchOffLine, rpcSetNodeDimming, rpcLineProfile, rpcNodeProfile, sunCalcExample, dataFromTerminalBroadcast})
|
||||
instance.send(0, { rpcSwitchOffLine, rpcSetNodeDimming, rpcLineProfile, rpcNodeProfile, sunCalcExample, dataFromTerminalBroadcast })
|
||||
})
|
||||
instance.on("5", _ => {
|
||||
exec("sudo tail -n 25 monitor.txt" , (err, stdout, stderr) => {
|
||||
if (err || stderr) instance.send(0,{err, stderr});
|
||||
else instance.send(0,stdout);
|
||||
exec("sudo tail -n 25 monitor.txt", (err, stdout, stderr) => {
|
||||
if (err || stderr) instance.send(0, { err, stderr });
|
||||
else instance.send(0, stdout);
|
||||
})
|
||||
})
|
||||
instance.on("6", _ => {
|
||||
exec("sudo tail -n 25 err.txt" , (err, stdout, stderr) => {
|
||||
if (err || stderr) instance.send(0,{err, stderr});
|
||||
else instance.send(0,stdout);
|
||||
exec("sudo tail -n 25 err.txt", (err, stdout, stderr) => {
|
||||
if (err || stderr) instance.send(0, { err, stderr });
|
||||
else instance.send(0, stdout);
|
||||
})
|
||||
})
|
||||
};
|
||||
instance.on("7", _ => {
|
||||
instance.send(0, FLOW.deviceStatus);
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
const rpcSwitchOffLine =
|
||||
const rpcSwitchOffLine =
|
||||
{
|
||||
"topic": "v1/gateway/rpc",
|
||||
"content": {
|
||||
|
|
@ -90,7 +92,7 @@ const rpcSetNodeDimming =
|
|||
}
|
||||
}
|
||||
|
||||
const rpcLineProfile =
|
||||
const rpcLineProfile =
|
||||
{
|
||||
"topic": "v1/gateway/rpc",
|
||||
"content": {
|
||||
|
|
@ -212,7 +214,7 @@ const rpcNodeProfile =
|
|||
}
|
||||
}
|
||||
|
||||
const sunCalcExample = {
|
||||
const sunCalcExample = {
|
||||
dusk_no_offset: '20:18',
|
||||
dawn_no_offset: '05:19',
|
||||
dusk: '20:18',
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ exports.output = 1;
|
|||
exports.author = 'Jakub Klena';
|
||||
exports.icon = 'plug';
|
||||
exports.version = '1.0.8';
|
||||
exports.options = { 'name':'', 'types': '["emergency", "critical", "error", "alert"]', 'message_includes':'["is responding again"]', 'tag_on_include':'[{"user_id":"U072JE5JUQG", "includes":["Electrometer", "Twilight sensor"]}]', 'slack_channel':'' };
|
||||
exports.options = { 'name': '', 'types': '["emergency", "critical", "error", "alert"]', 'message_includes': '["is responding again"]', 'tag_on_include': '[{"user_id":"U072JE5JUQG", "includes":["Electrometer", "Twilight sensor"]}]', 'slack_channel': '' };
|
||||
|
||||
exports.html = `<div class="padding">
|
||||
<div class="row">
|
||||
|
|
@ -37,7 +37,7 @@ exports.install = function(instance) {
|
|||
if (!running) return;
|
||||
let value = response.data;
|
||||
if (typeof value !== 'object') return;
|
||||
|
||||
|
||||
let can = false
|
||||
var k = Object.keys(value);
|
||||
var interested = JSON.parse(instance.options.types);
|
||||
|
|
@ -57,11 +57,11 @@ exports.install = function(instance) {
|
|||
let icon = ':totaljs:';
|
||||
let type = value[k[0]][0]['values']['_event']['type'];
|
||||
let source = value[k[0]][0]['values']['_event']['source']['func'];
|
||||
let message = value[k[0]][0]['values']['_event']['message'];
|
||||
let message = value[k[0]][0]['values']['_event']['message']['en'];
|
||||
let message_data = value[k[0]][0]['values']['_event']['message_data'];
|
||||
let tag = '';
|
||||
|
||||
switch(type){
|
||||
switch (type) {
|
||||
case 'debug':
|
||||
icon = ':beetle:';
|
||||
break;
|
||||
|
|
@ -89,15 +89,15 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
// Check if this message includes one of the strings we are watching for
|
||||
for (const msg of msg_incl){
|
||||
if (message.includes(msg)){
|
||||
for (const msg of msg_incl) {
|
||||
if (message.includes(msg)) {
|
||||
if (msg == 'is responding again') icon = ':large_green_circle:';
|
||||
can = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check if message is one of the types we are watching for
|
||||
if (interested.includes(type)){
|
||||
if (interested.includes(type)) {
|
||||
can = true;
|
||||
}
|
||||
|
||||
|
|
@ -105,10 +105,10 @@ exports.install = function(instance) {
|
|||
|
||||
|
||||
// Check for each person tags based on what the message includes
|
||||
for (const person of tags){
|
||||
for (const msg of person.includes){
|
||||
if (message.includes(msg)){
|
||||
tag += '<@'+person.user_id+'> ';
|
||||
for (const person of tags) {
|
||||
for (const msg of person.includes) {
|
||||
if (message.includes(msg)) {
|
||||
tag += '<@' + person.user_id + '> ';
|
||||
break; // Break out from this person checks as they are already tagged now
|
||||
}
|
||||
}
|
||||
|
|
@ -116,46 +116,46 @@ exports.install = function(instance) {
|
|||
// Now that all people are tagged add new line symbol
|
||||
if (tag != '') tag += '\n';
|
||||
|
||||
let send_data = tag+instance.options.name+' '+type.toUpperCase()+'\n*Source*: '+source+'\n*Message*: '+message;
|
||||
let send_data = tag + instance.options.name + ' ' + type.toUpperCase() + '\n*Source*: ' + source + '\n*Message*: ' + message;
|
||||
if (message_data) {
|
||||
send_data += '\nData: '+message_data;
|
||||
send_data += '\nData: ' + message_data;
|
||||
}
|
||||
|
||||
let ignore_msg = false
|
||||
if (message.includes('Configuration of dimming profile to node no')){
|
||||
for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){
|
||||
if (FLOW["savedSlackMessages"][i].message == message){
|
||||
if (message.includes('Configuration of dimming profile to node no')) {
|
||||
for (let i = 0; i < FLOW["savedSlackMessages"].length; i++) {
|
||||
if (FLOW["savedSlackMessages"][i].message == message) {
|
||||
ignore_msg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ignore_msg){
|
||||
FLOW["savedSlackMessages"].push({message, 'dateandtime': Date.now()});
|
||||
if (timer === null){
|
||||
timer = setTimeout(checkSavedMessages, 60*60000);
|
||||
if (!ignore_msg) {
|
||||
FLOW["savedSlackMessages"].push({ message, 'dateandtime': Date.now() });
|
||||
if (timer === null) {
|
||||
timer = setTimeout(checkSavedMessages, 60 * 60000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore_msg){
|
||||
instance.send2({'msg':send_data,'bot_name':instance.options.name+' '+type.toUpperCase(),'bot_icon':icon,'channel':instance.options.slack_channel});
|
||||
if (!ignore_msg) {
|
||||
instance.send2({ 'msg': send_data, 'bot_name': instance.options.name + ' ' + type.toUpperCase(), 'bot_icon': icon, 'channel': instance.options.slack_channel });
|
||||
}
|
||||
});
|
||||
|
||||
function checkSavedMessages(){
|
||||
function checkSavedMessages() {
|
||||
var d = Date.now();
|
||||
d = d - 86400000; // older then 24hr
|
||||
var a = [];
|
||||
//Remove msgs older then 24hr
|
||||
for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){
|
||||
if (FLOW["savedSlackMessages"][i].dateandtime > d){
|
||||
for (let i = 0; i < FLOW["savedSlackMessages"].length; i++) {
|
||||
if (FLOW["savedSlackMessages"][i].dateandtime > d) {
|
||||
a.push(FLOW["savedSlackMessages"][i]);
|
||||
}
|
||||
}
|
||||
FLOW["savedSlackMessages"] = a;
|
||||
|
||||
if (FLOW["savedSlackMessages"].length > 0) {
|
||||
timer = setTimeout(checkSavedMessages, 60*60000);
|
||||
timer = setTimeout(checkSavedMessages, 60 * 60000);
|
||||
} else {
|
||||
timer = null;
|
||||
}
|
||||
|
|
@ -163,7 +163,7 @@ exports.install = function(instance) {
|
|||
|
||||
instance.reconfigure = function() {
|
||||
try {
|
||||
if (!FLOW["savedSlackMessages"]){
|
||||
if (!FLOW["savedSlackMessages"]) {
|
||||
FLOW["savedSlackMessages"] = [];
|
||||
}
|
||||
|
||||
|
|
@ -183,5 +183,4 @@ exports.install = function(instance) {
|
|||
instance.on('options', instance.reconfigure);
|
||||
setTimeout(instance.reconfigure, 10000);
|
||||
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ exports.install = function(instance) {
|
|||
|
||||
logger.debug(exports.title, "installed");
|
||||
|
||||
instance.on("close", function(){
|
||||
instance.on("close", function() {
|
||||
clearInterval(startRead);
|
||||
})
|
||||
|
||||
|
|
@ -42,24 +42,25 @@ exports.install = function(instance) {
|
|||
|
||||
try {
|
||||
|
||||
if(temperatureAddress === "") throw "Thermometer: temperatureAddress is not defined";
|
||||
if (temperatureAddress === "") throw "Thermometer: temperatureAddress is not defined";
|
||||
|
||||
exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => {
|
||||
|
||||
if(!error)
|
||||
{
|
||||
if (!error) {
|
||||
parseData(stdout)
|
||||
return;
|
||||
}
|
||||
|
||||
counter++;
|
||||
if(counter == NUMBER_OF_FAILURES_TO_SEND_ERROR) sendNotification("Thermometer_main", rvoTbName, "thermometer_is_not_responding", {}, {"Error": error}, SEND_TO.tb, instance, "thermometer");
|
||||
monitor.info("Thermometer is not responding", error);
|
||||
instance.send(SEND_TO.dido_controller, {status: "NOK-thermometer"});
|
||||
if (counter == NUMBER_OF_FAILURES_TO_SEND_ERROR) {
|
||||
sendNotification("Thermometer_main", rvoTbName, "thermometer_is_not_responding", {}, { "Error": error }, SEND_TO.tb, instance, "thermometer");
|
||||
monitor.info("Thermometer is not responding", error);
|
||||
}
|
||||
instance.send(SEND_TO.dido_controller, { status: "NOK-thermometer" });
|
||||
});
|
||||
|
||||
}
|
||||
catch(err) {
|
||||
catch (err) {
|
||||
errLogger.error(exports.title, err);
|
||||
clearInterval(startRead);
|
||||
}
|
||||
|
|
@ -70,12 +71,12 @@ exports.install = function(instance) {
|
|||
data = parseFloat(data);
|
||||
//logger.debug("Thermometer", data);
|
||||
|
||||
if(isNaN(data)) {
|
||||
if (isNaN(data)) {
|
||||
errLogger.error("Thermometer sends invalid data");
|
||||
return;
|
||||
}
|
||||
|
||||
if(counter > NUMBER_OF_FAILURES_TO_SEND_ERROR) //1 hour
|
||||
if (counter > NUMBER_OF_FAILURES_TO_SEND_ERROR) //1 hour
|
||||
{
|
||||
instance.send(SEND_TO.debug, "Thermometer - temperature data are comming again");
|
||||
sendNotification("Thermometer_parseData", rvoTbName, "thermometer_is_responding_again", {}, "", SEND_TO.tb, instance, "thermometer");
|
||||
|
|
@ -85,7 +86,7 @@ exports.install = function(instance) {
|
|||
"temperature": Number(data.toFixed(2)),
|
||||
}
|
||||
|
||||
instance.send(SEND_TO.dido_controller, {values: values});
|
||||
instance.send(SEND_TO.dido_controller, { values: values });
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ let saveTelemetryOnError = true;//backup_on_failure overrides this value
|
|||
//------------------------
|
||||
|
||||
let rollers;
|
||||
if(createTelemetryBackup) rollers = require('streamroller');
|
||||
if (createTelemetryBackup) rollers = require('streamroller');
|
||||
|
||||
const noSqlFileSizeLimit = 4194304;//use 5MB - 4194304
|
||||
let insertNoSqlCounter = 0;
|
||||
|
|
@ -70,14 +70,14 @@ let lastRestoreTime = 0;
|
|||
// if there is an error in client connection, flow logs to monitor.txt. Not to log messages every second, we use sendClientError variable
|
||||
let sendClientError = true;
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
process.on('uncaughtException', function(err) {
|
||||
|
||||
errLogger.error('uncaughtException:', err.message)
|
||||
errLogger.error(err.stack);
|
||||
|
||||
//TODO
|
||||
//send to service
|
||||
|
||||
|
||||
//process.exit(1);
|
||||
})
|
||||
|
||||
|
|
@ -96,22 +96,19 @@ exports.install = function(instance) {
|
|||
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 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(SEND_TO.services, {[wsmqttName]: wsmqtt_status});
|
||||
function sendWsStatus() {
|
||||
instance.send(SEND_TO.services, { [wsmqttName]: wsmqtt_status });
|
||||
}
|
||||
|
||||
|
||||
function main()
|
||||
{
|
||||
if(!FLOW.dbLoaded) return;
|
||||
function main() {
|
||||
if (!FLOW.dbLoaded) return;
|
||||
|
||||
loadSettings();
|
||||
clearInterval(sendWsStatus);
|
||||
|
|
@ -119,11 +116,9 @@ exports.install = function(instance) {
|
|||
}
|
||||
|
||||
//set opts according to db settings
|
||||
function loadSettings()
|
||||
{
|
||||
function loadSettings() {
|
||||
|
||||
if(instance.options.host !== "")
|
||||
{
|
||||
if (instance.options.host !== "") {
|
||||
//override settings from database
|
||||
var o = instance.options;
|
||||
opts = {
|
||||
|
|
@ -139,13 +134,12 @@ exports.install = function(instance) {
|
|||
|
||||
console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
else {
|
||||
|
||||
const SETTINGS = FLOW.GLOBALS.settings;
|
||||
backup_on_failure = SETTINGS.backup_on_failure;
|
||||
saveTelemetryOnError = backup_on_failure;
|
||||
|
||||
|
||||
restore_from_backup = SETTINGS.restore_from_backup;
|
||||
restore_backup_wait = SETTINGS.restore_backup_wait;
|
||||
|
||||
|
|
@ -170,8 +164,7 @@ exports.install = function(instance) {
|
|||
connectToTbServer();
|
||||
}
|
||||
|
||||
function connectToTbServer()
|
||||
{
|
||||
function connectToTbServer() {
|
||||
var url = "mqtt://" + opts.host + ":" + opts.port;
|
||||
console.log("MQTT URL: ", url);
|
||||
|
||||
|
|
@ -179,7 +172,7 @@ exports.install = function(instance) {
|
|||
|
||||
client.on('connect', function() {
|
||||
instance.status("Connected", "green");
|
||||
monitor.info("MQTT client connected");
|
||||
//monitor.info("MQTT client connected");
|
||||
|
||||
sendClientError = true;
|
||||
clientReady = true;
|
||||
|
|
@ -198,31 +191,31 @@ exports.install = function(instance) {
|
|||
TRY(function() {
|
||||
|
||||
message = JSON.parse(message);
|
||||
if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
|
||||
client.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1});
|
||||
instance.send(SEND_TO.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}});
|
||||
if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
|
||||
client.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, { qos: 1 });
|
||||
instance.send(SEND_TO.rpcCall, { "device": message.device, "id": message.data.id, "RPC response": { "success": true } });
|
||||
}
|
||||
|
||||
}, () => instance.debug('MQTT: Error parsing data', message));
|
||||
}
|
||||
|
||||
instance.send(SEND_TO.rpcCall, {"topic":topic, "content":message });
|
||||
instance.send(SEND_TO.rpcCall, { "topic": topic, "content": message });
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
clientReady = false;
|
||||
wsmqtt_status = 'disconnected';
|
||||
|
||||
|
||||
instance.status("Disconnected", "red");
|
||||
instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !"});
|
||||
instance.send(SEND_TO.debug, { "message": "Client CLOSE signal received !" });
|
||||
});
|
||||
|
||||
client.on('error', function(err) {
|
||||
instance.status("Err: "+ err.code, "red");
|
||||
instance.send(SEND_TO.debug, {"message":"Client ERROR signal received !", "error":err, "opt":opts });
|
||||
if(sendClientError) {
|
||||
monitor.info('MQTT client error', err);
|
||||
sendClientError = false;
|
||||
instance.status("Err: " + err.code, "red");
|
||||
instance.send(SEND_TO.debug, { "message": "Client ERROR signal received !", "error": err, "opt": opts });
|
||||
if (sendClientError) {
|
||||
monitor.info('MQTT client error', err);
|
||||
sendClientError = false;
|
||||
}
|
||||
clientReady = false;
|
||||
wsmqtt_status = 'disconnected';
|
||||
|
|
@ -238,45 +231,39 @@ exports.install = function(instance) {
|
|||
|
||||
instance.on('1', function(data) {
|
||||
|
||||
if(clientReady)
|
||||
{
|
||||
//do we have some data in backup file? if any, process data from database
|
||||
if(saveTelemetryOnError)
|
||||
{
|
||||
if (clientReady) {
|
||||
//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 (!processingData) processDataFromDatabase();
|
||||
}
|
||||
|
||||
|
||||
let stringifiedJson = JSON.stringify(data.data);
|
||||
client.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1});
|
||||
client.publish("v1/gateway/telemetry", stringifiedJson, { qos: 1 });
|
||||
|
||||
//backup telemetry
|
||||
if(createTelemetryBackup)
|
||||
{
|
||||
if (createTelemetryBackup) {
|
||||
data.data.id = UID();
|
||||
nosqlBackup.insert(data.data);
|
||||
|
||||
insertBackupNoSqlCounter++;
|
||||
if(insertBackupNoSqlCounter > 150)
|
||||
{
|
||||
let options = {compress: true};
|
||||
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
|
||||
{
|
||||
//logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
|
||||
instance.send(SEND_TO.debug, {"message":"Client unavailable. Data not sent !", "data": data.data });
|
||||
|
||||
if(saveTelemetryOnError)
|
||||
{
|
||||
}
|
||||
else {
|
||||
//logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
|
||||
instance.send(SEND_TO.debug, { "message": "Client 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();
|
||||
|
||||
|
|
@ -289,72 +276,63 @@ exports.install = function(instance) {
|
|||
|
||||
|
||||
instance.close = function(done) {
|
||||
if(clientReady){
|
||||
if (clientReady) {
|
||||
client.end();
|
||||
clearInterval(sendWsStatusVar);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function getDbBackupFileCounter(type)
|
||||
{
|
||||
|
||||
function getDbBackupFileCounter(type) {
|
||||
var files = fs.readdirSync(__dirname + "/../databases");
|
||||
|
||||
let counter = 0;
|
||||
for(var i = 0; i < files.length; i++)
|
||||
{
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
|
||||
if(files[i] == "tbdata.nosql") continue;
|
||||
if (files[i] == "tbdata.nosql") continue;
|
||||
|
||||
if(files[i].endsWith(".nosql"))
|
||||
{
|
||||
if (files[i].endsWith(".nosql")) {
|
||||
|
||||
let pos = files[i].indexOf(".");
|
||||
if(pos > -1)
|
||||
{
|
||||
if (pos > -1) {
|
||||
|
||||
let fileCounter = counter;
|
||||
let firstDigit = files[i].slice(0, pos);
|
||||
|
||||
fileCounter = parseInt(firstDigit);
|
||||
if(isNaN(fileCounter)) fileCounter = 0;
|
||||
if (isNaN(fileCounter)) fileCounter = 0;
|
||||
//console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
|
||||
|
||||
if(type == "max")
|
||||
{
|
||||
if(fileCounter > counter)
|
||||
{
|
||||
|
||||
if (type == "max") {
|
||||
if (fileCounter > counter) {
|
||||
counter = fileCounter;
|
||||
}
|
||||
}
|
||||
else if(type == "min")
|
||||
{
|
||||
if(counter == 0) counter = fileCounter;
|
||||
else if (type == "min") {
|
||||
if (counter == 0) counter = fileCounter;
|
||||
|
||||
if(fileCounter < counter)
|
||||
{
|
||||
if (fileCounter < counter) {
|
||||
counter = fileCounter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(type == "max") counter++;
|
||||
|
||||
if (type == "max") counter++;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
const makeBackupFromDbFile = async () => {
|
||||
|
||||
if(!saveTelemetryOnError) return;
|
||||
if (!saveTelemetryOnError) return;
|
||||
|
||||
//to avoid large file: tbdata.nosql
|
||||
|
||||
//init value is 0!
|
||||
if(insertNoSqlCounter > 0)
|
||||
{
|
||||
if (insertNoSqlCounter > 0) {
|
||||
--insertNoSqlCounter;
|
||||
return;
|
||||
}
|
||||
|
|
@ -366,8 +344,7 @@ exports.install = function(instance) {
|
|||
var stats = fs.statSync(source);
|
||||
var fileSizeInBytes = stats.size;
|
||||
|
||||
if(fileSizeInBytes > noSqlFileSizeLimit)
|
||||
{
|
||||
if (fileSizeInBytes > noSqlFileSizeLimit) {
|
||||
|
||||
let counter = 1;
|
||||
counter = getDbBackupFileCounter("max");
|
||||
|
|
@ -381,21 +358,20 @@ exports.install = function(instance) {
|
|||
//clear tbdata.nosql
|
||||
fs.writeFileSync(source, "");
|
||||
fs.truncateSync(source, 0);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const processDataFromDatabase = async () => {
|
||||
|
||||
if(restore_from_backup <= 0) return;
|
||||
|
||||
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)
|
||||
{
|
||||
if ((diff / 1000) < restore_backup_wait) {
|
||||
//console.log("*********restore_backup_wait", diff, restore_backup_wait);
|
||||
return;
|
||||
}
|
||||
|
|
@ -409,60 +385,55 @@ exports.install = function(instance) {
|
|||
let dataBase = 'tbdata';
|
||||
|
||||
var nosql;
|
||||
if(counter == 0) dataBase = 'tbdata';
|
||||
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(clientReady) {
|
||||
|
||||
for (let i = 0; i < records.length; i++) {
|
||||
if (clientReady) {
|
||||
|
||||
let item = records[i];
|
||||
let id = item.id;
|
||||
|
||||
if(id !== undefined)
|
||||
{
|
||||
if (id !== undefined) {
|
||||
//console.log("------------processDataFromDatabase - remove", id, dataBase, i);
|
||||
|
||||
try {
|
||||
|
||||
let message = JSON.parse(JSON.stringify(item));
|
||||
delete message.id;
|
||||
|
||||
client.publish("v1/gateway/telemetry", JSON.stringify(message), {qos:1});
|
||||
|
||||
|
||||
client.publish("v1/gateway/telemetry", JSON.stringify(message), { qos: 1 });
|
||||
|
||||
//remove from database
|
||||
await promisifyBuilder(nosql.remove().where("id", id));
|
||||
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
//process error
|
||||
console.log("processDataFromDatabase", error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
processingData = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(records.length > 0)
|
||||
{
|
||||
if (records.length > 0) {
|
||||
//clean backup file
|
||||
if(counter > 0) nosql.clean();
|
||||
if (counter > 0) nosql.clean();
|
||||
}
|
||||
|
||||
//no data in db, remove
|
||||
if(records.length == 0)
|
||||
{
|
||||
if(counter > 0) nosql.drop();
|
||||
if (records.length == 0) {
|
||||
if (counter > 0) nosql.drop();
|
||||
}
|
||||
|
||||
const d = new Date();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue