Send to rado platform; show_dbdata, db loads after start

This commit is contained in:
rasta5man 2024-12-02 16:57:26 +01:00
parent ed0fe5b15d
commit f63ac50497
22 changed files with 6380 additions and 2279 deletions

View file

@ -20,9 +20,9 @@ key:string|weight:string|sk:string|en:string
+|power_supply_works_correctly|NOTICE|Napájací zdroj pracuje správne|Power supply works correctly|............... +|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_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|............... +|battery_level_is_ok|NOTICE|Batéria má správnu úroveň napätia|Battery level is OK|...............
+|door_has_been_open|NOTICE|Dvere boli otvorené|Door has been open|............... +|door_opened|NOTICE|Dvere boli otvorené|Door has been opeed|...............
+|door_has_been_closed|NOTICE|Dvere boli zatvorené|Door has been closed|............... +|door_closed|NOTICE|Dvere boli zatvorené|Door has been closed|...............
+|door_has_been_open_without_permision_alarm_is_on|WARNING|Dvere boli otvorené bez povolania - zapnutá siréna|Door has been open without permision - alarm is on|............... +|door_opened_without_permission|WARNING|Dvere boli otvorené bez povoeania - zapnutá siréna|Door has been oed without permision - alarm is on|...............
+|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}|............... +|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|||............... +|local_database_is_corrupted|CRITICAL|||...............
+|electrometer_nok|ERROR|Elektromer neodpovedá|Electrometer is not responding|............... +|electrometer_nok|ERROR|Elektromer neodpovedá|Electrometer is not responding|...............

View file

@ -1,2 +1,2 @@
rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number rvo_name:string|lang:string|temperature_adress: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
+|rvo_senica_39_10.0.0.132|en|28.427B45920702|48.70826502|17.28455203|192.168.252.1|rvo_senica_39_10.0.0.132|qzSNuCNrLP4OL1v47YEe|1883|0|68|unipi|ttyUSB0|1|20|5|........................................... +|rvo_senica_42_10.0.0.118|en|28.427B45920702|48.70826502|17.28455203|192.168.252.1|rvo_senica_42_10.0.0.118|QMvF7etEvbYMMr8Q6baP|1883|0|59|unipi|ttyUSB0|1|20|5|6|3|..............

View file

404
flow/cloudmqttconnect.js Normal file
View file

@ -0,0 +1,404 @@
exports.id = 'cloudmqttconnect';
exports.title = 'Cloud connect mqtt';
exports.group = 'MQTT';
exports.color = '#888600';
exports.version = '1.0.2';
exports.icon = 'sign-out';
exports.input = 1;
exports.output = 2;
exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" };
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="topic" data-jc-config="required:true" class="m">topic</div>
</div>
</div>
</div>`;
const { promisifyBuilder } = require('./helper/db_helper');
const fs = require('fs');
const mqtt = require('mqtt');
const SEND_TO = {
debug: 0,
rpcCall: 1,
}
//CONFIG
let saveTelemetryOnError = true;//backup_on_failure overrides this value
//------------------------
const noSqlFileSizeLimit = 4194304;//use 5MB - 4194304
let insertNoSqlCounter = 0;
let insertBackupNoSqlCounter = 0;
let processingData = false;
let backup_on_failure = true;//== saveTelemetryOnError - create backup client send failure
let restore_from_backup = 50; //how many rows process at once?
let restore_backup_wait = 3;//wait seconds
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;
const nosql = NOSQL('tbdatacloud');
exports.install = function(instance) {
var client;
var opts;
var clientReady = false;
let o = null; //options
function main()
{
loadSettings();
}
//set opts according to db settings
function loadSettings()
{
o = instance.options;
opts = {
host: o.host,
port: o.port,
clientId: o.clientid,
username: o.username,
rejectUnauthorized: false,
resubscribe: false
};
console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
connectToTbServer();
}
function connectToTbServer()
{
var url = "mqtt://" + opts.host + ":" + opts.port;
console.log("MQTT URL: ", url);
client = mqtt.connect(url, opts);
client.on('connect', function() {
client.subscribe(`${o.topic}_backward`, (err) => {
if (!err) {
console.log("MQTT subscribed");
}
});
instance.status("Connected", "green");
clientReady = true;
sendClientError = true;
});
client.on('reconnect', function() {
client.subscribe(`${o.topic}_backward`, (err) => {
if (!err) {
console.log("MQTT subscribed");
}
});
instance.status("Reconnecting", "yellow");
clientReady = false;
});
client.on('message', function(topic, message) {
// message is type of buffer
message = message.toString();
if (message[0] === '{') {
TRY(function() {
message = JSON.parse(message);
if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
client.publish(`${o.topic}_forward`, `{"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":o.topic, "content":message });
});
client.on('close', function(err) {
clientReady = false;
if (err && err.toString().indexOf('Error')) {
instance.status("Err: "+err.code, "red");
instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !", "error":err, "opt":opts });
} else {
instance.status("Disconnected", "red");
instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !", "error":err, "opt":opts });
}
client.reconnect();
});
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) {
console.log('MQTT client error', err);
sendClientError = false;
}
clientReady = false;
});
}
instance.on('0', function(data) {
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(clientReady)
{
client.publish(`${o.topic}_forward`, data.data, {qos: 1});
//console.log("ondata..",data.data)
// Pokad ten error na 38 chápem tak tento parameter MUSÍ byt string...
// Tak to musim dekódovat na strane Cloudu zas
}
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)
{
try {
let d = JSON.parse(data.data);
//create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
makeBackupFromDbFile();
//write to tb
d.id = UID();
nosql.insert(d);
} catch(e) {
console.log("cloudconnect - unable to parse data from wsmqtt");
}
}
}
});
instance.close = function(done) {
if(clientReady){
client.end();
}
};
function getDbBackupFileCounter(type)
{
var files = fs.readdirSync(__dirname + "/../databases");
let counter = 0;
for(var i = 0; i < files.length; i++)
{
if(files[i] == "tbdatacloud.nosql") continue;
if(files[i].endsWith(".nosql"))
{
let pos = files[i].indexOf(".");
if(pos > -1)
{
let fileCounter = counter;
let firstDigit = files[i].slice(0, pos);
fileCounter = parseInt(firstDigit);
if(isNaN(fileCounter)) fileCounter = 0;
//console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
if(type == "max")
{
if(fileCounter > counter)
{
counter = fileCounter;
}
}
else if(type == "min")
{
if(counter == 0) counter = fileCounter;
if(fileCounter < counter)
{
counter = fileCounter;
}
}
}
}
}
if(type == "max") counter++;
return counter;
}
const makeBackupFromDbFile = async () => {
if(!saveTelemetryOnError) return;
//to avoid large file: tbdata.nosql
//init value is 0!
if(insertNoSqlCounter > 0)
{
--insertNoSqlCounter;
return;
}
insertNoSqlCounter = 100;
let source = __dirname + "/../databases/tbdatacloud.nosql";
var stats = fs.statSync(source);
var fileSizeInBytes = stats.size;
if(fileSizeInBytes > noSqlFileSizeLimit)
{
let counter = 1;
counter = getDbBackupFileCounter("max");
let destination = __dirname + "/../databases/" + counter + "." + "tbdatacloud.nosql";
//make backup file
fs.copyFileSync(source, destination);
//fs.renameSync(p, p + "." + counter);
//clear tbdata.nosql
fs.writeFileSync(source, "");
fs.truncateSync(source, 0);
}
}
const processDataFromDatabase = async () => {
if(restore_from_backup <= 0) return;
//calculate diff
const now = new Date();
let currentTime = now.getTime();
let diff = currentTime - lastRestoreTime;
if( (diff / 1000) < restore_backup_wait)
{
//console.log("*********restore_backup_wait", diff, restore_backup_wait);
return;
}
processingData = true;
//get filename to process
let counter = getDbBackupFileCounter("min");
//we have some backup files
let dataBase = 'tbdata';
var nosql;
if(counter == 0) dataBase = 'tbdatacloud';
else dataBase = counter + "." + 'tbdatacloud';
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) {
let item = records[i];
let id = item.id;
if(id !== undefined)
{
//console.log("------------processDataFromDatabase - remove", id, dataBase, i);
try {
let o = JSON.parse(JSON.stringify(item));
delete o.id;
let message = JSON.stringify(o);
client.publish(`${o.topic}_forward`, message, {qos:1});
//console.log("db...", message)
//remove from database
await promisifyBuilder(nosql.remove().where("id", id));
} catch(error) {
//process error
console.log("processDataFromDatabase", error);
}
}
}
else
{
processingData = false;
return;
}
}
if(records.length > 0)
{
//clean backup file
if(counter > 0) nosql.clean();
}
//no data in db, remove
if(records.length == 0)
{
if(counter > 0) nosql.drop();
}
const d = new Date();
lastRestoreTime = d.getTime();
processingData = false;
}
instance.on('options', main);
main();
};

File diff suppressed because it is too large Load diff

3603
flow/cmd_manager131.js Normal file

File diff suppressed because it is too large Load diff

108
flow/db_init.js Normal file
View file

@ -0,0 +1,108 @@
exports.id = 'db_init';
exports.title = 'DB Initialization';
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.readme = `
# DB initialization
`;
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
const { initNotification } = require('./helper/notification_reporter');
exports.install = async function(instance) {
const dbNodes = TABLE("nodes");
const dbRelays = TABLE("relays");
const dbSettings = TABLE("settings");
const dbStatus = TABLE("status");
const dbPins = TABLE("pins");
const dbNotifications = TABLE("notifications");
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 responseStatus = await promisifyBuilder(dbStatus.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.statusData = responseStatus[0];
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"];
dbs.settings = {
edge_fw_version : "2024-11-04", //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"],
//dynamic values
masterNodeIsResponding : true, //cmd_manager
maintenance_mode : false,
}
FLOW.dbLoaded = true;
initNotification();
setTimeout(()=> {
console.log("DB_INIT - data loaded");
instance.send(0, "_")
}, 5000)
};

File diff suppressed because it is too large Load diff

View file

@ -3,8 +3,8 @@ exports.title = 'DIDO_Controller';
exports.version = '2.0.0'; exports.version = '2.0.0';
exports.group = 'Worksys'; exports.group = 'Worksys';
exports.color = '#2134B0'; exports.color = '#2134B0';
exports.input = 2; exports.input = 3;
exports.output = ["red", "white", "yellow"]; exports.output = ["red", "white", "yellow", "green"];
exports.click = false; exports.click = false;
exports.icon = 'bolt'; exports.icon = 'bolt';
exports.options = { edge: "undefined" }; exports.options = { edge: "undefined" };
@ -56,25 +56,31 @@ state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda
momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale zmena by sa mala ukázať aj na platforme momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale zmena by sa mala ukázať aj na platforme
*/ */
const dbStatus = TABLE("status");
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');
const bitwise = require('bitwise');
//globals const DataToTbHandler = require('./helper/DataToTbHandler');
//FIRMWARE version let tbHandler;
//TODO remove FLOW.OMS_edgeName variable, as we have FLOW.OMS_rvo_tbname
FLOW.OMS_edge_fw_version = "2024-09-23";//rok-mesiac-den
FLOW.OMS_edgeName = "";
FLOW.OMS_maintenance_mode = false;
//dynamic values const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
FLOW.OMS_masterNodeIsResponding = true; //cmd_manager const errorHandler = new ErrorToServiceHandler();
//FLOW.OMS_brokerready = false //wsmqttpublish
FLOW.OMS_no_voltage = new Set();//modbus_citysys - elektromer
//see loadSettings() in cmd_manager let ws = null;
FLOW.OMS_language = "en";//cmd_manager let rsPort = null;
FLOW.OMS_rvo_name = "";//cmd_manager
FLOW.OMS_rvo_tbname = "";//relaysData let pinsData;
FLOW.OMS_temperature_adress = "";//cmd_manager let relaysData;
//----------------------------------------------- let rvoTbName;
let GLOBALS; //FLOW global GLOBALS
let SETTINGS; // GLOBALS.settings
let controller_type;
let alarmStatus = "OFF"; let alarmStatus = "OFF";
@ -87,43 +93,6 @@ const SEND_TO = {
const TIME_AFTER_TEMPERATURE_NOK_STATUS = 3600; //seconds const TIME_AFTER_TEMPERATURE_NOK_STATUS = 3600; //seconds
const DIFFERENCE_TO_SEND_TEMPERATURE = 0.31; const DIFFERENCE_TO_SEND_TEMPERATURE = 0.31;
var log4js = require("log4js");
var path = require('path');
log4js.configure({
appenders: {
errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
console: { type: 'console' }
},
categories: {
errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
//another: { appenders: ['console'], level: 'trace' },
default: { appenders: ['console'], level: 'trace' }
}
});
const errLogger = log4js.getLogger("errLogs");
const logger = log4js.getLogger();
const monitor = log4js.getLogger("monitorLogs");
//console.log(path.join(__dirname, 'err.txt', "-----------------------------"));
/*
process.on('uncaughtException', function (err) {
errLogger.error('uncaughtException:', err.message)
errLogger.error(err.stack);
//process.exit(1);
})
*/
//USAGE
//logger.debug("text")
//monitor.info('info');
//errLogger.error("some error");
exports.install = function(instance) { exports.install = function(instance) {
@ -149,8 +118,6 @@ exports.install = function(instance) {
const twilight_sensor_array = []; const twilight_sensor_array = [];
let twilightError = false; let twilightError = false;
let edgeName = "";
monitor.info("DIDO_Relay_Controller installed"); monitor.info("DIDO_Relay_Controller installed");
//key is PIN number , line: 0 = RVO //key is PIN number , line: 0 = RVO
@ -172,15 +139,6 @@ exports.install = function(instance) {
}; };
*/ */
const dbPins = TABLE("pins");
let pinsData = {};//key is pin
const dbRelays = TABLE("relays");
let relaysData = {};//key is line
const dbStatus = TABLE("status");
let statusData = null;
//status for calculating Statecodes //status for calculating Statecodes
let deviceStatus = { //key is device name: temperature,.... let deviceStatus = { //key is device name: temperature,....
"state_of_main_switch": "Off", //Hlavný istič "state_of_main_switch": "Off", //Hlavný istič
@ -190,53 +148,32 @@ exports.install = function(instance) {
"temperature": "OK", //templomer "temperature": "OK", //templomer
"battery": "OK", //Batéria "battery": "OK", //Batéria
"power_supply": "OK", //Zdroj "power_supply": "OK", //Zdroj
"master_node": "OK", //MN - FLOW.OMS_masterNodeIsResponding "master_node": "OK", //MN - GLOBALS.settings.masterNodeIsResponding
"no_voltage": "OK", //FLOW.OMS_no_voltage - výpadok napätia na fáze "no_voltage": "OK", //GLOBALS.settings.no_voltage - výpadok napätia na fáze
"state_of_breaker": {}, //"Off",//Istič "state_of_breaker": {}, //"Off",//Istič
"state_of_contactor": {}, //"Off",//Stykač "state_of_contactor": {}, //"Off",//Stykač
"twilight_sensor": "OK" //lux sensor "twilight_sensor": "OK" //lux sensor
}; };
const SerialPort = require('serialport');
const WebSocket = require('ws');
let ws = null; function main() {
let rsPort = null;
const { runSyncExec } = require('./helper/serialport_helper.js'); GLOBALS = FLOW.GLOBALS;
const { bytesToInt, resizeArray } = require('./helper/utils'); SETTINGS = FLOW.GLOBALS.settings;
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js'); rvoTbName = SETTINGS.rvoTbName;
const { sendNotification } = require('./helper/notification_reporter.js'); pinsData = GLOBALS.pinsData;
const bitwise = require('bitwise'); relaysData = GLOBALS.relaysData;
statusData = GLOBALS.statusData;
const DataToTbHandler = require('./helper/DataToTbHandler.js'); tbHandler = new DataToTbHandler(SEND_TO.tb)
const tbHandler = new DataToTbHandler(SEND_TO.tb);
tbHandler.setSender(exports.title); tbHandler.setSender(exports.title);
const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js'); controller_type = SETTINGS.controller_type //"lm" or "unipi" //logicMachine
const errorHandler = new ErrorToServiceHandler();
//let useTurnOffCounter = false;
//let turnOffCounter = 0;
let controller_type = FLOW.OMS_controller_type //"lm" or "unipi" //logicMachine
if(controller_type == "") controller_type = "lm"; if(controller_type == "") controller_type = "lm";
console.log(exports.title, "controller type: ", controller_type);
async function loadAllDb()
{
let responsePins = await promisifyBuilder(dbPins.find());
pinsData = makeMapFromDbResult(responsePins, "pin");
let responseRelays = await promisifyBuilder(dbRelays.find());
relaysData = makeMapFromDbResult(responseRelays, "line");
let responseStatus = await promisifyBuilder(dbStatus.find());
statusData = responseStatus[0]; // {thermometer: 'OK', em: 'OK', twilight_sensor: 'OK'}
deviceStatus["temperature"] = statusData.thermometer; deviceStatus["temperature"] = statusData.thermometer;
FLOW.OMS_rvo_tbname = relaysData[0].tbname; console.log(exports.title, "controller type: ", controller_type);
if(controller_type === "lm") if(controller_type === "lm")
{ {
@ -254,7 +191,8 @@ exports.install = function(instance) {
function initialSetting() function initialSetting()
{ {
//force turn off relays & set tbname //force turn off relays
let keys = Object.keys(pinsData); let keys = Object.keys(pinsData);
for(let i = 0; i < keys.length; i++) for(let i = 0; i < keys.length; i++)
{ {
@ -266,15 +204,12 @@ exports.install = function(instance) {
if(relaysData[line] != undefined) if(relaysData[line] != undefined)
{ {
pinsData[key].tbname = relaysData[line].tbname; pinsData[key].tbname = relaysData[line].tbname;
//relaysData[line].contactor = 0;
relaysData[line].contactor = 0;
} }
else else
{ {
errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line); errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line);
sendNotification("set port ", rvoTbName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance );
//sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", SEND_TO.tb, instance, null );
sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance );
} }
} }
@ -285,36 +220,23 @@ exports.install = function(instance) {
//this will modify database //this will modify database
let forceTurnOff = true; let forceTurnOff = true;
turnOffLine(line, pin, forceTurnOff, "turn off on startup"); turnLine("off", line, pin, forceTurnOff, "turn off on startup");
} }
} }
//report RVO version relaysData[0].tbname; //report RVO version relaysData[0].tbname;
let values = {}; let values = {};
values["edge_fw_version"] = FLOW.OMS_edge_fw_version; values["edge_fw_version"] = SETTINGS.edge_fw_version;
values["maintenance_mode"] = FLOW.OMS_maintenance_mode; values["maintenance_mode"] = SETTINGS.maintenance_mode;
edgeName = relaysData[0].tbname; sendTelemetry(values, rvoTbName);
FLOW.OMS_edgeName = edgeName;
dataToTb = {
[edgeName]: [
{
"ts": Date.now(),
"values": values
}
]
}
instance.send(SEND_TO.tb, dataToTb);
let time = 5*1000; let time = 5*1000;
setTimeout(function(){ 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()", edgeName, "flow_start", {}, "", SEND_TO.tb, instance ); sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance);
monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version); monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
}, time); }, time);
} }
@ -339,20 +261,16 @@ exports.install = function(instance) {
//set port //set port
rsPort.write(Buffer.from(setRSPortData), function(err) { rsPort.write(Buffer.from(setRSPortData), function(err) {
if(!err) {
monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)"); monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
turnOffAlarm(); turnAlarm("off");
//useTurnOffCounter = true;
//turnOffCounter = relaysData.length - 1;
initialSetting(); initialSetting();
}
}) })
}).catch(function(reason) { }).catch(function(reason) {
//instance.send(SEND_TO.debug, exports.title + " runSyncExec - promise rejected:" + reason);
errLogger.error(exports.title + " runSyncExec - promise rejected:" + reason); errLogger.error(exports.title + " runSyncExec - promise rejected:" + reason);
errorHandler.sendMessageToService(exports.title + " runSyncExec - promise rejected:" + reason); errorHandler.sendMessageToService(exports.title + " runSyncExec - promise rejected:" + reason);
}); });
@ -402,7 +320,6 @@ exports.install = function(instance) {
}) })
rsPort.open(); rsPort.open();
} }
@ -417,7 +334,7 @@ exports.install = function(instance) {
ws.onopen = function open() { ws.onopen = function open() {
instance.send(0, exports.title + " running"); instance.send(0, exports.title + " running");
turnOffAlarm(); turnAlarm("off");
// useTurnOffCounter = true; // useTurnOffCounter = true;
// turnOffCounter = relaysData.length - 1; // turnOffCounter = relaysData.length - 1;
@ -480,7 +397,7 @@ exports.install = function(instance) {
{ {
previousValues["temperature"]["value"] = value; previousValues["temperature"]["value"] = value;
values['temperature'] = value; values['temperature'] = value;
sendTelemetry(values, FLOW.OMS_rvo_tbname); sendTelemetry(values, rvoTbName);
} }
return; return;
} }
@ -516,24 +433,11 @@ exports.install = function(instance) {
} }
} }
// ! do we need requests every minute ???
// const startRequests = () => {
// console.log("startRequest function called");
// start = setInterval(() => {
// // console.log("data from evok requested");
// ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"}));
// // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]}));
// }, 150000)
// }
instance.on("close", () => { instance.on("close", () => {
if(rsPort) rsPort.close(); if(rsPort) rsPort.close();
if(ws) ws.close(); if(ws) ws.close();
clearInterval(sendRebuildTasksAt11);
}) })
loadAllDb();
function getPin(line) function getPin(line)
{ {
@ -556,52 +460,32 @@ exports.install = function(instance) {
} }
function turnOnAlarm() function turnAlarm(onOrOff)
{ {
if(FLOW.OMS_maintenance_mode) return; let value = 0;
if(onOrOff == "on") value = 1;
alarmStatus = "ON"; if(value == 1 && SETTINGS.maintenance_mode) return;
if(rsPort)
{
let arr = [0x55];
arr.push( 13 );
arr.push( 0 );
arr.push( 1 );
rsPort.write(Buffer.from(arr), function(err) {
logger.debug("sirena zapnuta");
});
}
else if(ws)
{
let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1};
ws.send(JSON.stringify(cmd));
logger.debug("sirena zapnuta");
}
}
function turnOffAlarm()
{
alarmStatus = "OFF"; alarmStatus = "OFF";
if(value == 1) alarmStatus = "ON";
if(rsPort) if(rsPort)
{ {
let arr = [0x55]; let arr = [0x55];
arr.push(13); arr.push(13);
arr.push(0); arr.push(0);
arr.push( 0 ); arr.push(value);
rsPort.write(Buffer.from(arr), function(err) { rsPort.write(Buffer.from(arr), function(err) {
logger.debug("sirena vypnuta"); logger.debug(`sirena - ${onOrOff}`);
}); });
} }
else if(ws) else if(ws)
{ {
let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0}; let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": value};
ws.send(JSON.stringify(cmd)); ws.send(JSON.stringify(cmd));
logger.debug("sirena vypnuta"); logger.debug(`sirena - ${onOrOff}`);
} }
} }
@ -609,9 +493,7 @@ exports.install = function(instance) {
function reportLineStatus(line) function reportLineStatus(line)
{ {
//Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false). //Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false).
let tbname = relaysData[line].tbname; let tbname = relaysData[line].tbname;
let bits = []; let bits = [];
if(deviceStatus["state_of_breaker"][line] == "On") if(deviceStatus["state_of_breaker"][line] == "On")
@ -631,130 +513,35 @@ exports.install = function(instance) {
let byte = bitwise.byte.write(bits.reverse()); let byte = bitwise.byte.write(bits.reverse());
//console.log("line", line, bits, byte); //console.log("line", line, bits, byte);
sendTelemetry({statecode: byte}, tbname);
let values = {
statecode: byte
} }
let dataToTb = {
[tbname]: [ // turn line on or off
function turnLine(onOrOff, line, pin, force, info)
{ {
"ts": Date.now(), //onOrOff => "on" or "off"
"values": values let value = 0;
} if(onOrOff == "on") value = 1;
]
}
//console.log(values);
instance.send(SEND_TO.tb, dataToTb);
}
function turnOnLine(line, pin, force, info)
{
instance.send(SEND_TO.debug, "turn on line " + line );
if(force == undefined) force = false; if(force == undefined) force = false;
if(line == 0) if(line == 0)
{ {
if(alarmStatus == "ON") turnOffAlarm(); if(value == 1 && alarmStatus == "ON") turnAlarm("off");
FLOW.OMS_maintenance_mode = true; SETTINGS.maintenance_mode = value? true: false;
let values = {}; let values = {};
values["statecode"] = calculateStateCode(); values["statecode"] = calculateStateCode();
values["power_mode"] = "maintenance"; values["power_mode"] = value ? "maintenance": "Automatic";
let tbname = relaysData[line].tbname; sendTelemetry(values, rvoTbName);
sendTelemetry(values, tbname);
monitor.info("turnOnLine (line, FLOW.OMS_maintenance_mode)", line, FLOW.OMS_maintenance_mode, info);
monitor.info(`turnLine ${onOrOff} - (line, SETTINGS.maintenance_mode)`, line, SETTINGS.maintenance_mode, info);
return; return;
} }
if(pin === undefined) pin = getPin(line); if(pin === undefined) pin = getPin(line);
monitor.info("turnOnLine (line, pin, force)", line, pin, force, info);
if( pin === undefined)
{
monitor.info("pin is undefined!", line);
return;
}
if(!force)
{
if(relaysData[line].contactor == 1)
{
instance.send(SEND_TO.debug, "line is already on " + line );
logger.debug("turnOnLine: line is already on: ", line);
return;
}
}
// if(!rsPort.isOpen && !ws)
if(!rsPort && !ws)
{
errLogger.error("dido controller - port or websocket is not opened");
return;
}
if(rsPort)
{
let arr = [0x55];
arr.push( pin );
arr.push( 0 );
arr.push( 1 );
rsPort.write(Buffer.from(arr), function(err) {
if(err === undefined)
{
console.log("turnONLine zapisal do rsPortu", line, arr);
switchLogic(arr);
}
else
{
monitor.info("turnOnLine WRITE error", err);
}
});
}
else if(ws)
{
console.log("turnONLine pin (relay)", pin);
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1};
ws.send(JSON.stringify(cmd));
switchLogic(pin, 1)
}
}
function turnOffLine(line, pin, force, info)
{
if(force == undefined) force = false;
if(line == 0)
{
FLOW.OMS_maintenance_mode = false;
let values = {};
values["statecode"] = calculateStateCode();
values["power_mode"] = "automatic";
let tbname = relaysData[line].tbname;
sendTelemetry(values, tbname);
return;
}
if( pin === undefined) pin = getPin(line);
monitor.info("turnOffLine (line, pin, force)", line, pin, force, info);
if(pin === undefined) if(pin === undefined)
{ {
errLogger.error("pin is undefined!", line); errLogger.error("pin is undefined!", line);
@ -763,11 +550,10 @@ exports.install = function(instance) {
if(!force) if(!force)
{ {
if(relaysData[line].contactor == 0) if(relaysData[line].contactor == value)
{ {
instance.send(SEND_TO.debug, "line is already off " + line ); instance.send(SEND_TO.debug, `line is already ${onOrOff} ` + line );
logger.debug("turnOffLine: line already off:", line); logger.debug(`turnLine: line is already ${onOrOff} `, line);
return; return;
} }
} }
@ -784,33 +570,38 @@ exports.install = function(instance) {
let arr = [0x55]; let arr = [0x55];
arr.push(pin); arr.push(pin);
arr.push(0); arr.push(0);
arr.push( 0 ); arr.push(value);
rsPort.write(Buffer.from(arr), function(err) { rsPort.write(Buffer.from(arr), function(err) {
if(err === undefined) if(err === undefined)
{ {
console.log("turnOffLine zapisal do rsPort-u", line, arr); monitor.info(`turnLine ${onOrOff} zapisal do rsPort-u`, line, pin, arr, info);
switchLogic(arr); switchLogic(arr);
} }
else else
{ {
monitor.info("turnOffLine WRITE error", err); monitor.info(`turnLine ${onOrOff} WRITE error`, err);
} }
}); });
} }
else if(ws) else if(ws)
{ {
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
//monitor.info("turnOffLine pin (relay)", pin); monitor.info(`turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0}; let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": value};
ws.send(JSON.stringify(cmd)); ws.send(JSON.stringify(cmd));
switchLogic(pin, 0) switchLogic(pin, value)
} }
} }
// main opening
instance.on("2", _ => {
main();
})
//data from modbus_reader or temperature sensor or twilight sensor or other modbus device //data from modbus_reader or temperature sensor or twilight sensor or other modbus device
instance.on("0", flowdata => { instance.on("0", flowdata => {
@ -820,7 +611,7 @@ exports.install = function(instance) {
instance.send(SEND_TO.debug, flowdata.data); instance.send(SEND_TO.debug, flowdata.data);
// we handle nok status from modbus_reader component and thermometer // we handle nok status from modbus_reader component and thermometer
if(flowdata.data?.status) if("status" in flowdata.data)
{ {
const status = flowdata.data.status; const status = flowdata.data.status;
if(status == "NOK-twilight_sensor") if(status == "NOK-twilight_sensor")
@ -838,7 +629,7 @@ exports.install = function(instance) {
deviceStatus["temperature"] = "NOK"; deviceStatus["temperature"] = "NOK";
} }
} }
else if(flowdata.data?.values) else if("values" in flowdata.data)
{ {
const values = flowdata.data.values; const values = flowdata.data.values;
if(values.hasOwnProperty("twilight_sensor")) if(values.hasOwnProperty("twilight_sensor"))
@ -856,10 +647,10 @@ exports.install = function(instance) {
else if(values.hasOwnProperty("total_power") || values.hasOwnProperty("total_energy") || values.hasOwnProperty("power_factor") || values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_1_current")) else if(values.hasOwnProperty("total_power") || values.hasOwnProperty("total_energy") || values.hasOwnProperty("power_factor") || values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_1_current"))
{ {
deviceStatus["em"] = "OK"; deviceStatus["em"] = "OK";
FLOW.OMS_no_voltage.size > 0 ? deviceStatus["no_voltage"] = "NOK": deviceStatus["no_voltage"] = "OK"; SETTINGS.no_voltage.size > 0 ? deviceStatus["no_voltage"] = "NOK": deviceStatus["no_voltage"] = "OK";
} }
sendTelemetry(values, FLOW.OMS_rvo_tbname); sendTelemetry(values, rvoTbName);
} }
sendRvoStatus(); sendRvoStatus();
@ -878,10 +669,10 @@ exports.install = function(instance) {
let force = obj.force; let force = obj.force;
let info = obj.info; let info = obj.info;
if(obj.command == "turnOn") turnOnLine(line, undefined, force, info); if(obj.command == "turnOn") turnLine("on", line, undefined, force, info);
else if(obj.command == "turnOff") turnOffLine(line, undefined, force, info); else if(obj.command == "turnOff") turnLine("off", line, undefined, force, info);
else if(obj.command == "turnOnAlarm") turnOnAlarm(); else if(obj.command == "turnOnAlarm") turnAlarm("on");
else if(obj.command == "turnOffAlarm") turnOffAlarm(); else if(obj.command == "turnOffAlarm") turnAlarm("off");
//! ake data prichadzaju z cmd_manager.js ??? //! ake data prichadzaju z cmd_manager.js ???
//TODO transform to websocket //TODO transform to websocket
@ -899,11 +690,9 @@ exports.install = function(instance) {
function calculateStateCode() function calculateStateCode()
{ {
let bytes = [];
let bits = []; let bits = [];
//Hlavný istič - state_of_main_switch //Hlavný istič - state_of_main_switch => v rvo senica je to druhy door pre silovu cast (EM)
//TODO state_of main_switch is door contact in senica rvo - values should be "open" and "closed"
if(deviceStatus["state_of_main_switch"] == "closed") if(deviceStatus["state_of_main_switch"] == "closed")
{ {
bits.push(0); bits.push(0);
@ -914,7 +703,7 @@ exports.install = function(instance) {
} }
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY //Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
if(!FLOW.OMS_maintenance_mode) if(!SETTINGS.maintenance_mode)
{ {
if(deviceStatus["rotary_switch_state"] == "Manual") if(deviceStatus["rotary_switch_state"] == "Manual")
{ {
@ -1040,6 +829,10 @@ exports.install = function(instance) {
async function sendRvoStatus() { async function sendRvoStatus() {
// test if dbLoaded is ok to check
//if(!FLOW.dbLoaded) return;
if(SETTINGS === undefined) return;
const table = { const table = {
"OK": 1, "OK": 1,
"NOK": 0 "NOK": 0
@ -1055,7 +848,7 @@ exports.install = function(instance) {
"master_node_status": table[deviceStatus["master_node"]] "master_node_status": table[deviceStatus["master_node"]]
}; };
for (const phase of FLOW.OMS_no_voltage) dataToTb[`phase_${phase}_status`] = 0; for (const phase of SETTINGS.no_voltage) dataToTb[`phase_${phase}_status`] = 0;
//thermometer did not send data for more than a hour. Time in seconds //thermometer did not send data for more than a hour. Time in seconds
if(deviceStatus["temperature"] === "OK") if(deviceStatus["temperature"] === "OK")
@ -1071,7 +864,7 @@ exports.install = function(instance) {
dataToTb["status"] = checkRvoStatus(); dataToTb["status"] = checkRvoStatus();
dataToTb["statecode"] = calculateStateCode(); dataToTb["statecode"] = calculateStateCode();
sendTelemetry(dataToTb, FLOW.OMS_rvo_tbname); sendTelemetry(dataToTb, rvoTbName);
} }
@ -1083,7 +876,8 @@ exports.install = function(instance) {
let status = "OK"; let status = "OK";
for (const [key, value] of Object.entries(deviceStatus)) { for (const [key, value] of Object.entries(deviceStatus)) {
if(["em", "twilight_sensor", "temperature"].includes(key) && value == "NOK") status = "NOK"; //if(["em", "twilight_sensor", "temperature"].includes(key) && value == "NOK") status = "NOK";
if(["em", "twilight_sensor"].includes(key) && value == "NOK") status = "NOK";
} }
if(status == "OK") if(status == "OK")
@ -1093,7 +887,7 @@ exports.install = function(instance) {
for (const pinIndex of pinIndexes) { for (const pinIndex of pinIndexes) {
if (previousValues[pinIndex] === 0) { if (previousValues[pinIndex] === 0) {
if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && FLOW.OMS_maintenance_mode) continue; if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && SETTINGS.maintenance_mode) continue;
status = "NOK"; status = "NOK";
break; break;
} }
@ -1102,8 +896,8 @@ exports.install = function(instance) {
// battery status. If value is 1 - battery is NOK // battery status. If value is 1 - battery is NOK
if (previousValues[5] === 1) status = "NOK"; if (previousValues[5] === 1) status = "NOK";
if(!FLOW.OMS_masterNodeIsResponding) status = "NOK"; if(!SETTINGS.masterNodeIsResponding) status = "NOK";
if(FLOW.OMS_no_voltage.size > 0) status = "NOK"; if(SETTINGS.no_voltage.size > 0) status = "NOK";
return status; return status;
} }
@ -1135,7 +929,7 @@ exports.install = function(instance) {
if(obj == undefined) if(obj == undefined)
{ {
previousValues[pinIndex] = newPinValue; previousValues[pinIndex] = newPinValue;
logger.debug("dido-switchLogic ==> no pinIndex", pinIndex); //logger.debug("dido-switchLogic ==> no pinIndex", pinIndex);
return; return;
} }
@ -1155,14 +949,14 @@ exports.install = function(instance) {
// { // {
// if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) // if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
// { // {
// sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch"); // sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
// values["status"] = "NOK"; // values["status"] = "NOK";
// deviceStatus["state_of_main_switch"] = "Off"; // deviceStatus["state_of_main_switch"] = "Off";
// } // }
// else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) // else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
// { // {
// sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch"); // 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"] = "On";
// } // }
@ -1211,73 +1005,71 @@ exports.install = function(instance) {
//console.log("rotary_switch_state pin", pin2, pin3, value); //console.log("rotary_switch_state pin", pin2, pin3, value);
} }
//Zdroj - pin 4 //Zdroj - pin 4
else if (type === "power_supply") else if (type === "power_supply")
{ {
if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", SEND_TO.tb, instance); sendNotification("switchLogic", rvoTbName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
deviceStatus["power_supply"] = "NOK"; deviceStatus["power_supply"] = "NOK";
} }
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", SEND_TO.tb, instance); sendNotification("switchLogic", rvoTbName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
deviceStatus["power_supply"] = "OK"; deviceStatus["power_supply"] = "OK";
} }
} }
//Batéria - pin 5 //Batéria - pin 5
else if (type === "battery") else if (type === "battery")
{ {
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", SEND_TO.tb, instance); sendNotification("switchLogic", rvoTbName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
deviceStatus["battery"] = "NOK"; deviceStatus["battery"] = "NOK";
} }
else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", SEND_TO.tb, instance); sendNotification("switchLogic", rvoTbName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
deviceStatus["battery"] = "OK"; deviceStatus["battery"] = "OK";
} }
} }
//Dverový kontakt - pin 6 //Dverový kontakt - pin 6
//! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch" //! 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' //! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition'
else if(type == "door_condition" || type === "state_of_main_switch") else if(type == "door_condition" || type === "state_of_main_switch")
{ {
newPinValue === 0 ? value = "open" : value = "closed"; newPinValue === 0 ? value = "open" : value = "closed";
if (value === "open" && FLOW.OMS_maintenance_mode)
if (value === "open" && SETTINGS.maintenance_mode)
{ {
sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", SEND_TO.tb, instance, "rvo_door"); sendNotification("switchLogic", rvoTbName, "door_opened", {}, "", SEND_TO.tb, instance, "rvo_door");
} }
if (value === "open" && !FLOW.OMS_maintenance_mode) if (value === "open" && !SETTINGS.maintenance_mode)
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", SEND_TO.tb, instance); sendNotification("switchLogic", rvoTbName, "door_opened_without_permission", {}, "", SEND_TO.tb, instance, "rvo_door");
sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", SEND_TO.tb, instance, "rvo_door");
// zapneme sirenu // 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") // 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") turnOnAlarm(); if(type === "door_condition") turnAlarm("on");
} }
if (value === "closed") if (value === "closed")
{ {
if(alarmStatus == "ON") turnOffAlarm(); if(alarmStatus == "ON") turnAlarm("off");
//turnOffAlarm(); sendNotification("switchLogic", rvoTbName, "door_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
} }
deviceStatus[type] = value; deviceStatus[type] = value;
} }
//lux sensor //lux sensor
else if(type == "twilight_sensor") else if(type == "twilight_sensor")
{ {
@ -1309,14 +1101,15 @@ exports.install = function(instance) {
{ {
twilightError = true; twilightError = true;
let value = twilight_sensor_array.shift(); let value = twilight_sensor_array.shift();
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, SEND_TO.tb, instance );
newPinValue = 0; newPinValue = 0;
} }
else if (set.size !== 1 && twilightError) else if (set.size !== 1 && twilightError)
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance ); //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
twilightError = false; twilightError = false;
twilight_sensor_array.shift(); twilight_sensor_array.shift();
newPinValue = value; newPinValue = value;
} }
else if (set.size === 1 && twilightError) else if (set.size === 1 && twilightError)
@ -1339,12 +1132,12 @@ exports.install = function(instance) {
//else console.log("lux_sensor", value, diff); //else console.log("lux_sensor", value, diff);
} }
} }
else if(type == "state_of_contactor") else if(type == "state_of_contactor")
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", SEND_TO.tb, instance );
if(!(deviceStatus["state_of_contactor"][line] == value)) if(!(deviceStatus["state_of_contactor"][line] == value))
{ {
sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance ); sendNotification("switchLogic", rvoTbName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance );
} }
deviceStatus["state_of_contactor"][line] = value; deviceStatus["state_of_contactor"][line] = value;
@ -1353,34 +1146,45 @@ exports.install = function(instance) {
if(value === "On") value = true; if(value === "On") value = true;
else if(value === "Off") value = false; else if(value === "Off") value = false;
//modify table relays //TODO do we need to modify relays table with contactor value, if we do not use it on startup ??
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; let dataChanged = false;
if(relaysData[line].contactor != value) dataChanged = true; if(relaysData[line].contactor !== newPinValue) {
relaysData[line].contactor = value; dataChanged = true;
relaysData[line].contactor = newPinValue;
//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);
instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged});
reportLineStatus(line); reportLineStatus(line);
}
else //modify table relays
{ // dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
errLogger.error("modify table relays failed", err); // 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") else if(type === "state_of_breaker")
{ {
@ -1448,28 +1252,27 @@ exports.install = function(instance) {
if(type == "rotary_switch_state") if(type == "rotary_switch_state")
{ {
if(FLOW.OMS_maintenance_mode) value = "maintenance"; if(SETTINGS.maintenance_mode) value = "maintenance";
value = value.toLowerCase(); value = value.toLowerCase();
values["power_mode"] = value; values["power_mode"] = value;
} }
if(newPinValue != previousValues[pinIndex]) previousValues[pinIndex] = newPinValue; if(newPinValue != previousValues[pinIndex]) previousValues[pinIndex] = newPinValue;
if(FLOW.OMS_rvo_tbname == tbname) sendRvoStatus(); if(rvoTbName == tbname) sendRvoStatus();
if(Object.keys(values).length > 0 && tbname) sendTelemetry(values, tbname); if(Object.keys(values).length > 0 && tbname) sendTelemetry(values, tbname);
} }
function sendTelemetry(values, tbname) { function sendTelemetry(values, tbname, date=Date.now()) {
let dataToTb = { let dataToTb = {
[tbname]: [ [tbname]: [
{ {
"ts": Date.now(), "ts": date,
"values": values "values": values
} }
] ]
}; };
// instance.send(SEND_TO.tb, dataToTb);
tbHandler.sendToTb(dataToTb, instance); tbHandler.sendToTb(dataToTb, instance);
} }
@ -1496,8 +1299,6 @@ exports.install = function(instance) {
return (typeof item === "object" && !Array.isArray(item) && item !== null); return (typeof item === "object" && !Array.isArray(item) && item !== null);
} }
} //end of instance } //end of instance

View file

@ -49,13 +49,8 @@ class DataToTbHandler {
for(let i = 0; i < arrayOfValues.length; i++) for(let i = 0; i < arrayOfValues.length; i++)
{ {
ts = arrayOfValues[i].ts; ts = arrayOfValues[i].ts;
//console.log("sendToTb------------>before", arrayOfValues[i].values, tbname);
let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values); let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
//console.log("sendToTb------------>after", values);
if(!this.isEmptyObject(values)) if(!this.isEmptyObject(values))
{ {
arrayOfValuesToSend.push({ts: ts, values: values}); arrayOfValuesToSend.push({ts: ts, values: values});
@ -68,17 +63,6 @@ class DataToTbHandler {
return; return;
} }
/*
let dataToTb = {
[tbname]: [
{
"ts": Date.now(),
"values": values
}
]
}
*/
this.messageCounter++; this.messageCounter++;
let dataToTbModified = { let dataToTbModified = {

View file

@ -97,7 +97,7 @@ class ErrorToServiceHandler
console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender); console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender);
//TODO UGLY!!! //TODO UGLY!!!
if(this.projects_id === undefined) this.projects_id = FLOW.OMS_projects_id; if(this.projects_id === undefined) this.projects_id = FLOW.GLOBALS.settings.project_id;
/* /*
if(this.projects_id === undefined) if(this.projects_id === undefined)

View file

@ -1,72 +0,0 @@
//key is device, value = str
let sentValues= {};
function sendError(func, device, weight, str, extra, tb_output, instance, type) {
// if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
// return; // Allow debug messages only if CONFIG.debug is active
// }
let key = device;
if(type != undefined) key = type;
if(sentValues.hasOwnProperty(key))
{
if(sentValues[key] == str)
{
return;
}
}
sentValues[key] = str;
let content = {
"type": weight,
"status": "new",
"source": {
"func":func,
"component":instance.id,
"component_name":instance.name,
"edge":device
},
"message":str,
"message_data": extra
};
let msg = {};
msg[device] = [
{
"ts": Date.now(),
"values": {
"_event":content
}
}
];
// Msg can be outputted from components only after configuration
/*if (canSendErrData()){
sendBufferedErrors();
} else {
bufferError(msg);
}*/
instance.send(tb_output, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
}
let ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable
ALERT: "alert", // Action must be taken immidiately
CRITICAL: "critical", // Component unable to function
ERROR: "error", // Error, but component able to recover from it
WARNING: "warning", // Possibility of error, system running futher
NOTICE: "notice", // Significant message but not an error, things user might want to know about
INFO: "informational", // Info
DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
};
module.exports = {
sendError,
ERRWEIGHT
}

View file

@ -1,56 +0,0 @@
const ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable
ALERT: "alert", // Action must be taken immidiately
CRITICAL: "critical", // Component unable to function
ERROR: "error", // Error, but component able to recover from it
WARNING: "warning", // Possibility of error, system running futher
NOTICE: "notice", // Significant message but not an error, things user might want to know about
INFO: "informational", // Info
DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
};
function sendError(func, device, weight, str, extra){
if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
return; // Allow debug messages only if CONFIG.debug is active
}
let content = {
"type": weight,
"status": "new",
"source": {
"func":func,
"component":instance.id,
"component_name":instance.name,
"edge":myEdge
},
"message":str,
"message_data": extra
};
let msg = {};
msg[device] = [
{
"ts": Date.now(),
"values": {
"_event":content
}
}
];
// Msg can be outputted from components only after configuration
/*if (canSendErrData()){
sendBufferedErrors();
} else {
bufferError(msg);
}*/
instance.send(0, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
}
module.exports = {
sendError,
ERRWEIGHT,
}

30
flow/helper/logger.js Normal file
View file

@ -0,0 +1,30 @@
//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
var log4js = require("log4js");
var path = require('path');
log4js.configure({
appenders: {
errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../../", 'err.txt') },
monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../../", 'monitor.txt') },
console: { type: 'console' }
},
categories: {
errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
//another: { appenders: ['console'], level: 'trace' },
default: { appenders: ['console'], level: 'trace' }
}
});
const errLogger = log4js.getLogger("errLogs");
const logger = log4js.getLogger();
const monitor = log4js.getLogger("monitorLogs");
//USAGE
//logger.debug("text")
//monitor.info('info');
//errLogger.error("some error");
module.exports = { errLogger, logger, monitor };

View file

@ -1,10 +1,6 @@
const { promisifyBuilder, makeMapFromDbResult } = require('./db_helper.js');
const dbNotifications = TABLE("notifications");
//key is device, value = str //key is device, value = str
let sentValues= {}; let sentValues= {};
let notificationsData = {}; let notificationsData = null;
let ERRWEIGHT = { let ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable EMERGENCY: "emergency", // System unusable
@ -24,12 +20,9 @@ function getKey(map, val) {
//https://stackoverflow.com/questions/41117799/string-interpolation-on-variable //https://stackoverflow.com/questions/41117799/string-interpolation-on-variable
var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]); var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]);
async function initNotifications()
{
let response = await promisifyBuilder(dbNotifications.find());
notificationsData = makeMapFromDbResult(response, "key");
console.log("initNotifications done" ); function initNotification() {
notificationsData = FLOW.GLOBALS.notificationsData;
} }
function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) { function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) {
@ -39,7 +32,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
let storeToSendValues = true; let storeToSendValues = true;
if(saveKey == undefined) storeToSendValues = false; if(saveKey == undefined) storeToSendValues = false;
let lang = FLOW.OMS_language; let lang = FLOW.GLOBALS.settings.language;
if(lang != "en" || lang != "sk") lang = "en"; if(lang != "en" || lang != "sk") lang = "en";
let tpl = key; let tpl = key;
@ -55,7 +48,8 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
} }
else else
{ {
console.error("sendNotification: Notifications: undefined key", key, func, notificationsData); //console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
console.error("sendNotification: Notifications: undefined key", key, func );
return false; return false;
} }
@ -91,7 +85,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
if(storeToSendValues) sentValues[saveKey] = tpl; if(storeToSendValues) sentValues[saveKey] = tpl;
let str = FLOW.OMS_rvo_name; let str = FLOW.GLOBALS.settings.rvo_name;
if(str != "") str = str + ": "; if(str != "") str = str + ": ";
str = str + tpl; str = str + tpl;
@ -132,6 +126,6 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
module.exports = { module.exports = {
sendNotification, sendNotification,
initNotifications, ERRWEIGHT,
ERRWEIGHT initNotification
} }

View file

@ -40,18 +40,17 @@ async function writeData(port, data, readbytes, timeout){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// If first item in data array is 255, we just write broadcast command to rsPort // If first item in data array is 255, we just write broadcast command to rsPort
// We wait 3 seconds and resolve([ "b", "r", "o", "a", "d", "c", "a", "s", "t" ]) // We wait 3 seconds and resolve(["broadcast"])
// It is important to resolve with array // It is important to resolve with array
if(data[0] == 255) { if(data[0] == 255) {
port.write(Buffer.from(data), function(err) { port.write(Buffer.from(data), function(err) {
if (err) { if (err) {
port.removeListener('data', callback);
reject(err.message); reject(err.message);
} }
}); });
setTimeout(resolve, 3000, [ "b", "r", "o", "a", "d", "c", "a", "s", "t" ]); setTimeout(resolve, 3000, ["broadcast"]);
return; return;
} }

View file

@ -3,12 +3,9 @@ exports.title = 'Info sender';
exports.version = '1.0.0'; exports.version = '1.0.0';
exports.group = 'Worksys'; exports.group = 'Worksys';
exports.color = '#2134B0'; exports.color = '#2134B0';
exports.input = 1; exports.input = 2;
exports.output = 1 exports.output = 1
exports.click = false;
exports.author = 'oms-is';
exports.icon = 'bolt'; exports.icon = 'bolt';
exports.options = { edge: "undefined" };
const { networkInterfaces } = require('os'); const { networkInterfaces } = require('os');
@ -22,13 +19,12 @@ exports.html = `<div class="padding">
exports.readme = `# send all data to projects.worksys.io, required to monitor status of controller(unipi)`; exports.readme = `# send all data to projects.worksys.io, required to monitor status of controller(unipi)`;
const fs = require('fs'); exports.install = function(instance) {
var path = require('path');
exports.install = async function(instance) {
let id;
let allValues = {}; let allValues = {};
let sendAllValuesInterval; let sendAllValuesInterval;
let configured = false;
let now = new Date(); let now = new Date();
console.log(exports.title, "INSTALLED", now.toLocaleString("sk-SK")); console.log(exports.title, "INSTALLED", now.toLocaleString("sk-SK"));
@ -48,22 +44,18 @@ exports.install = async function(instance) {
} }
} }
function sendValues() function sendValues()
{ {
const id = FLOW.OMS_projects_id; if(!configured) return;
if(Object.keys(allValues).length > 0) if(Object.keys(allValues).length > 0)
{ {
if(id !== undefined) if(id)
{ {
delete allValues.__force__; delete allValues.__force__;
let dataToSend = {...allValues}; let dataToSend = {...allValues};
dataToSend.id = id; dataToSend.id = id;
dataToSend.ipAddresses = ipAddresses; dataToSend.ipAddresses = ipAddresses;
//dataToSend.notify_date = new Date().toISOString().slice(0, 19).replace('T', ' ');
//console.log(exports.title, "------------>sendValues", dataToSend);
instance.send(0, dataToSend); instance.send(0, dataToSend);
@ -71,7 +63,7 @@ exports.install = async function(instance) {
} }
else else
{ {
console.log(exports.title, "unable to send data, id is undefined"); console.log(exports.title, "unable to send data, no id");
} }
} }
@ -81,10 +73,14 @@ exports.install = async function(instance) {
clearInterval(sendAllValuesInterval); clearInterval(sendAllValuesInterval);
}) })
instance.on("data", (flowdata) => { instance.on("0", _ => {
id = FLOW.GLOBALS.settings.project_id;
configured = true;
})
instance.on("1", flowdata => {
allValues = { ...allValues, ...flowdata.data}; allValues = { ...allValues, ...flowdata.data};
//console.log("DATA RECEIVED", flowdata.data); //console.log("DATA RECEIVED", flowdata.data);
//__force__ //__force__

View file

@ -3,6 +3,7 @@ exports.title = 'Modbus reader';
exports.version = '2.0.0'; exports.version = '2.0.0';
exports.group = 'Worksys'; exports.group = 'Worksys';
exports.color = '#2134B0'; exports.color = '#2134B0';
exports.input = 1;
exports.output = ["red", "white", "yellow"]; exports.output = ["red", "white", "yellow"];
exports.click = false; exports.click = false;
exports.author = 'Rastislav Kovac'; exports.author = 'Rastislav Kovac';
@ -31,7 +32,10 @@ const SEND_TO = {
const numberOfNotResponding = {}; const numberOfNotResponding = {};
let tbName = null; let tbName = null;
let mainSocket; let mainSocket;
//number of phases inRVO
let phases;
//phases where voltage is 0 (set)
let noVoltage;
exports.install = function(instance) { exports.install = function(instance) {
@ -55,10 +59,19 @@ exports.install = function(instance) {
// lampSwitchNotification helper variables // lampSwitchNotification helper variables
this.onNotificationSent = false; this.onNotificationSent = false;
this.offNotificationSent = false; this.offNotificationSent = false;
this.phases = this.buildPhases();
this.startSocket(); this.startSocket();
} }
buildPhases = () => {
let a = [];
for (let i = 1; i<= phases; i++) {
a.push(`Phase_${i}_voltage`)
}
return a;
}
startSocket = () => { startSocket = () => {
let obj = this; let obj = this;
@ -228,9 +241,7 @@ exports.install = function(instance) {
this.allValues = {}; this.allValues = {};
break; break;
} }
} }
} }
setNewStream = () => setNewStream = () =>
@ -282,7 +293,7 @@ exports.install = function(instance) {
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 => { Object.keys(values).map(singleValue => {
if (["Phase_1_voltage", "Phase_2_voltage", "Phase_3_voltage"].includes(singleValue)) if (this.phases.includes(singleValue))
{ {
let l = singleValue.split("_"); let l = singleValue.split("_");
let phase = parseInt(l[1]); let phase = parseInt(l[1]);
@ -291,13 +302,13 @@ exports.install = function(instance) {
if(values[singleValue] == 0) if(values[singleValue] == 0)
{ {
FLOW.OMS_no_voltage.add(phase); 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') // console.log('no voltage')
} }
else else
{ {
FLOW.OMS_no_voltage.delete(phase); noVoltage.delete(phase);
// console.log('voltage detected') // 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);
} }
@ -333,15 +344,20 @@ exports.install = function(instance) {
return Object.keys(objectName).length === 0 && objectName.constructor === Object; return Object.keys(objectName).length === 0 && objectName.constructor === Object;
} }
setTimeout(() => { function main() {
phases = FLOW.GLOBALS.settings.phases;
tbName = FLOW.GLOBALS.settings.rvoTbName;
noVoltage = FLOW.GLOBALS.settings.no_voltage;
mainSocket = new SocketWithClients(); mainSocket = new SocketWithClients();
tbName = FLOW.OMS_rvo_tbname;
// this notification is to show, that flow (unipi) has been restarted // this notification is to show, that flow (unipi) has been restarted
sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance); sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance);
}
}, 25000); instance.on("0", function(_) {
main();
})
} }

241
flow/show_dbdata.js Normal file
View file

@ -0,0 +1,241 @@
exports.id = 'showdb';
exports.title = 'Show db data';
exports.group = 'Worksys';
exports.color = '#888600';
exports.version = '1.0.2';
exports.icon = 'sign-out';
exports.input = 7;
exports.output = 1;
const { exec } = require('child_process');
exports.install = function(instance) {
instance.on("0", _ => {
instance.send(0, FLOW.GLOBALS.settings);
})
instance.on("1", _ => {
instance.send(0, FLOW.GLOBALS.relaysData);
})
instance.on("2", _ => {
instance.send(0, FLOW.GLOBALS.nodesData);
})
instance.on("3", _ => {
instance.send(0, FLOW.GLOBALS.pinsData);
})
instance.on("4", _ => {
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);
})
})
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);
})
})
};
const rpcSwitchOffLine =
{
"topic": "v1/gateway/rpc",
"content": {
"device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
"data": {
"id": 8,
"method": "set_command",
"params": {
"entities": [
{
"entity_type": "edb_line",
"tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
}
],
"command": "switch",
"payload": {
"value": false
}
}
}
}
}
const rpcSetNodeDimming =
{
"topic": "v1/gateway/rpc",
"content": {
"device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
"data": {
"id": 10,
"method": "set_command",
"params": {
"entities": [
{
"entity_type": "street_luminaire",
"tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
}
],
"command": "dimming",
"payload": {
"value": 5
}
}
}
}
}
const rpcLineProfile =
{
"topic": "v1/gateway/rpc",
"content": {
"device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
"data": {
"id": 9,
"method": "set_profile",
"params": {
"entities": [
{
"entity_type": "edb_line",
"tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
}
],
"payload": {
"intervals": [
{
"value": 0,
"end_time": "20:00",
"start_time": "13:00"
},
{
"value": 1,
"end_time": "05:30",
"start_time": "20:00"
},
{
"value": 0,
"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": 0,
"dusk_astro_clock_offset": 0,
"dawn_lux_sensor_time_window": 30,
"dusk_lux_sensor_time_window": 30,
"dawn_astro_clock_time_window": 60,
"dusk_astro_clock_time_window": 60
}
}
}
}
}
const rpcNodeProfile =
{
"topic": "v1/gateway/rpc",
"content": {
"device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
"data": {
"id": 11,
"method": "set_profile",
"params": {
"entities": [
{
"entity_type": "street_luminaire",
"tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
}
],
"payload": {
"intervals": [
{
"cct": 3000,
"value": 0,
"end_time": "17:50",
"start_time": "13:00"
},
{
"cct": 3000,
"value": 100,
"end_time": "21:30",
"start_time": "17:50"
},
{
"cct": 3000,
"value": 0,
"end_time": "13:00",
"start_time": "07:10"
},
{
"cct": 3000,
"value": 50,
"end_time": "00:00",
"start_time": "21:30"
},
{
"cct": 3000,
"value": 10,
"end_time": "04:30",
"start_time": "00:00"
},
{
"cct": 3000,
"value": 100,
"end_time": "07:10",
"start_time": "04: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": 30,
"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
}
}
}
}
}
const sunCalcExample = {
dusk_no_offset: '20:18',
dawn_no_offset: '05:19',
dusk: '20:18',
dusk_hours: 20,
dusk_minutes: 18,
dawn: '05:19',
dawn_hours: 5,
dawn_minutes: 19,
dusk_time: 1715278688962,
dawn_time: 1715224744357,
dusk_astro_clock_offset: 0,
dawn_astro_clock_offset: 0
}
const dataFromTerminalBroadcast = {
address: 4294967295,
byte1: 0,
byte2: 0,
byte3: 0,
byte4: 96,
name: "Time Schedule settings",
recipient: 2,
register: 8,
rw: 1
}

View file

@ -11,9 +11,6 @@ exports.options = { 'name':'', 'types': '["emergency", "critical", "error", "ale
exports.html = `<div class="padding"> exports.html = `<div class="padding">
<div class="row"> <div class="row">
<div class="col-md-12">
<div data-jc="textbox" data-jc-path="name" data-jc-config="required:true">@(Name of this server)</div>
</div>
<div class="col-md-12"> <div class="col-md-12">
<div data-jc="textbox" data-jc-path="slack_channel" data-jc-config="required:false">@(Slack channel to receive the alerts)</div> <div data-jc="textbox" data-jc-path="slack_channel" data-jc-config="required:false">@(Slack channel to receive the alerts)</div>
</div> </div>
@ -170,11 +167,12 @@ exports.install = function(instance) {
FLOW["savedSlackMessages"] = []; FLOW["savedSlackMessages"] = [];
} }
instance.options.name = FLOW.GLOBALS.settings.rvo_name;
if (instance.options.name) { if (instance.options.name) {
instance.status('Running'); instance.status('Running');
running = true; running = true;
} else { } else {
instance.status('Please enter name', 'red'); instance.status('Please run options again', 'red');
running = false; running = false;
} }
} catch (e) { } catch (e) {
@ -183,5 +181,7 @@ exports.install = function(instance) {
}; };
instance.on('options', instance.reconfigure); instance.on('options', instance.reconfigure);
instance.reconfigure(); setTimeout(instance.reconfigure, 10000);
}; };

View file

@ -2,6 +2,7 @@ exports.id = 'thermometer';
exports.title = 'Thermometer'; exports.title = 'Thermometer';
exports.group = 'Worksys'; exports.group = 'Worksys';
exports.color = '#5CB36D'; exports.color = '#5CB36D';
exports.input = 1;
exports.version = '1.0.3'; exports.version = '1.0.3';
exports.output = ["red", "white", "blue"]; exports.output = ["red", "white", "blue"];
exports.author = 'Rastislav Kovac'; exports.author = 'Rastislav Kovac';
@ -9,7 +10,9 @@ exports.icon = 'thermometer-three-quarters';
exports.readme = `# Getting temperature values for RVO. In case of LM, you need device address. In case of unipi, evok sends values, in case thermometer is installed`; exports.readme = `# Getting temperature values for RVO. In case of LM, you need device address. In case of unipi, evok sends values, in case thermometer is installed`;
const instanceSendTo = { const { errLogger, logger, monitor } = require('./helper/logger');
const SEND_TO = {
debug: 0, debug: 0,
tb: 1, tb: 1,
dido_controller: 2 dido_controller: 2
@ -18,56 +21,16 @@ const instanceSendTo = {
//read temperature - frequency //read temperature - frequency
let timeoutMin = 5;//minutes let timeoutMin = 5;//minutes
var path = require('path');
var log4js = require("log4js");
log4js.configure({
appenders: {
errLogs: { type: 'file', filename: path.join(__dirname + "/../", 'err.txt') },
monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
console: { type: 'console' }
},
categories: {
errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
//another: { appenders: ['console'], level: 'trace' },
default: { appenders: ['console'], level: 'trace' }
}
});
const errLogger = log4js.getLogger("errLogs");
const logger = log4js.getLogger();
const monitor = log4js.getLogger("monitorLogs");
//logger.debug("text")
//monitor.info('info');
//errLogger.error("some error");
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper');
const dbSettings = TABLE("settings");
let temperatureAddress = "";
async function loadSettings()
{
//todo global FLOW.OMS_edgeName is making problem, so we load it here as well, it should not be
let responseSettings = await promisifyBuilder(dbSettings.find());
temperatureAddress = responseSettings[0]["temperature_adress"];
}
loadSettings();
exports.install = function(instance) { exports.install = function(instance) {
const { exec } = require('child_process'); const { exec } = require('child_process');
const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter'); const { sendNotification } = require('./helper/notification_reporter');
let startRead; let startRead;
let dataToTb;
let counter = 0; let counter = 0;
let rvoTbName = "";
let edgeName = ""; let temperatureAddress = "";
logger.debug(exports.title, "installed"); logger.debug(exports.title, "installed");
@ -76,11 +39,11 @@ exports.install = function(instance) {
}) })
const start = function() { const main = function() {
try { try {
if(FLOW.OMS_controller_type === "unipi") if(FLOW.GLOBALS.settings.controller_type === "unipi")
{ {
clearInterval(startRead); clearInterval(startRead);
return; return;
@ -88,71 +51,23 @@ exports.install = function(instance) {
if(temperatureAddress === "") throw "gettemperature: temperatureAddress is not defined"; if(temperatureAddress === "") throw "gettemperature: temperatureAddress is not defined";
logger.debug("FLOW.OMS_temperature_adress", FLOW.OMS_temperature_adress);
exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => { exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => {
edgeName = FLOW.OMS_edgeName; if(!error)
if(edgeName !== "")
{ {
if(error) parseData(stdout)
{
if(FLOW.OMS_brokerready == undefined)
{
logger.debug("gettemparature - FLOW.OMS_brokerready is undefined");
setTimeout(function(){
start();
}, 3000);
return; return;
} }
if(FLOW.OMS_brokerready) sendNotification("main", rvoTbName, "thermometer_is_not_responding", {}, {"Error": error}, SEND_TO.tb, instance, "thermometer");
{ monitor.info("Thermometer is not responding", error);
//sendNotification("start", edgeName, ERRWEIGHT.WARNING, "Thermometer is not responding", {"Error": error}, instanceSendTo.tb, instance, "thermometer"); instance.send(SEND_TO.dido_controller, {status: "NOK-thermometer"});
sendNotification("start", edgeName, "thermometer_is_not_responding", {}, {"Error": error}, instanceSendTo.tb, instance, "thermometer");
}
let status = "NOK";
dataToTb = {
[edgeName]: [
{
"ts": Date.now(),
"values": {
"status": status
}
}
]
}
monitor.info("Thermometer is not responding", error, FLOW.OMS_brokerready);
// instance.send(instanceSendTo.tb, dataToTb); // poslat stav nok do tb, ak to handluje dido_controller ??
instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"});
}
else parseData(stdout);
}
else
{
monitor.info("gettemperature: edgeName is not defined", FLOW.OMS_edgeName);
setTimeout(function(){
start();
}, 3000);
return;
}
//instance.send({"Temp":stdout,"stderr":stderr,"err":error});
}); });
} }
catch(err) { catch(err) {
errLogger.error(exports.title, err); errLogger.error(exports.title, err);
clearInterval(startRead);
} }
} }
@ -166,30 +81,17 @@ exports.install = function(instance) {
if(counter > 290) if(counter > 290)
{ {
instance.send(instanceSendTo.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break"); instance.send(SEND_TO.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break");
sendNotification("parseData", rvoTbName, "thermometer_is_responding_again", {}, "", SEND_TO.tb, instance, "thermometer");
//sendNotification("parseData", edgeName, ERRWEIGHT.NOTICE, "Thermometer is working again", "", instanceSendTo.tb, instance, "thermometer");
if(FLOW.OMS_brokerready) sendNotification("parseData", edgeName, "thermometer_is_responding_again", {}, "", instanceSendTo.tb, instance, "thermometer");
} }
logger.debug("gettemperature", data); logger.debug("gettemperature", data);
const values = { const values = {
"temperature": Number(data.toFixed(2)), "temperature": Number(data.toFixed(2)),
"status": "OK"
} }
dataToTb = { instance.send(SEND_TO.dido_controller, {values: values});
[edgeName]: [
{
"ts": Date.now(),
"values":values
}
]
}
instance.send(instanceSendTo.tb, dataToTb);
instance.send(instanceSendTo.dido_controller, values);
counter = 0; counter = 0;
} else { } else {
@ -200,24 +102,21 @@ exports.install = function(instance) {
//ked je problem 1 den //ked je problem 1 den
let day = 24 * 60 / timeoutMin; let day = 24 * 60 / timeoutMin;
if ( counter > day && counter < day + 2 ) { if ( counter > day && counter < day + 2 ) {
//sendNotification("parseData", edgeName, ERRWEIGHT.WARNING, "Thermometer receives invalid data", "", instanceSendTo.tb, instance, "thermometer"); //sendNotification("parseData", rvoTbName, ERRWEIGHT.WARNING, "Thermometer receives invalid data", "", SEND_TO.tb, instance, "thermometer");
sendNotification("parseData", edgeName, "thermometer_sends_invalid_data", {}, "", instanceSendTo.tb, instance, "thermometer"); sendNotification("parseData", rvoTbName, "thermometer_sends_invalid_data", {}, "", SEND_TO.tb, instance, "thermometer");
instance.send(instanceSendTo.debug, "[Get temperature component] - no temperature data from RVO for more than 1 day"); instance.send(SEND_TO.debug, "[Get temperature component] - no temperature data from RVO for more than 1 day");
instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"}); instance.send(SEND_TO.dido_controller, {status: "NOK-thermometer"});
} }
} }
} }
setTimeout(function(){ instance.on("data", _ => {
start(); temperatureAddress = FLOW.GLOBALS.settings.temperature_address;
}, 10000); rvoTbName = FLOW.GLOBALS.settings.rvoTbName;
startRead = setInterval(main, timeoutMin * 1000 * 60);
startRead = setInterval(start, timeoutMin * 1000 * 60); main();
})
//testing
//setInterval(() => {instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"})}, 180000);
}; };

View file

@ -4,12 +4,9 @@ exports.group = 'MQTT';
exports.color = '#888600'; exports.color = '#888600';
exports.version = '1.0.2'; exports.version = '1.0.2';
exports.icon = 'sign-out'; exports.icon = 'sign-out';
exports.input = 1; exports.input = 2;
exports.output = ["red", "white", "blue"]; exports.output = 4;
exports.author = 'Daniel Segeš';
exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" }; exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" };
exports.npm = ['mqtt'];
exports.html = `<div class="padding"> exports.html = `<div class="padding">
<div class="row"> <div class="row">
@ -41,21 +38,22 @@ Added:
- rpc response - rpc response
`; `;
const instanceSendTo = { const { promisifyBuilder } = require('./helper/db_helper');
const { errLogger, monitor } = require('./helper/logger');
const fs = require('fs');
const mqtt = require('mqtt');
const SEND_TO = {
debug: 0, debug: 0,
rpcCall: 1, rpcCall: 1,
services: 2 services: 2
} }
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
//CONFIG //CONFIG
let useLog4js = true;
let createTelemetryBackup = true; let createTelemetryBackup = true;
let saveTelemetryOnError = true;//backup_on_failure overrides this value let saveTelemetryOnError = true;//backup_on_failure overrides this value
//------------------------ //------------------------
var fs = require('fs');
let rollers; let rollers;
if(createTelemetryBackup) rollers = require('streamroller'); if(createTelemetryBackup) rollers = require('streamroller');
@ -64,56 +62,18 @@ let insertNoSqlCounter = 0;
let insertBackupNoSqlCounter = 0; let insertBackupNoSqlCounter = 0;
let processingData = false; let processingData = false;
let backup_on_failure = false;//== saveTelemetryOnError - create backup broker send failure let backup_on_failure = false;//== saveTelemetryOnError - create backup client send failure
let restore_from_backup = 0; //how many rows process at once? let restore_from_backup = 0; //how many rows process at once?
let restore_backup_wait = 0;//wait seconds let restore_backup_wait = 0;//wait seconds
let lastRestoreTime = 0; let lastRestoreTime = 0;
let errLogger; // if there is an error in client connection, flow logs to monitor.txt. Not to log messages every second, we use sendClientError variable
let logger; let sendClientError = true;
let monitor;
//TODO brokerready and sendBrokerError seems to be the same. Moreover, we use FLOW_OMS_brokerready variable!!
//
// if there is an error in broker connection, flow logs to monitor.txt. Not to log messages every second, we use sendBrokerError variable
let sendBrokerError = true;
if(useLog4js)
{
var path = require('path');
var log4js = require("log4js");
log4js.configure({
appenders: {
errLogs: { type: 'file', filename: path.join(__dirname + "/../", 'err.txt') },
monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
console: { type: 'console' }
},
categories: {
errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
//another: { appenders: ['console'], level: 'trace' },
default: { appenders: ['console'], level: 'trace' }
}
});
errLogger = log4js.getLogger("errLogs");
logger = log4js.getLogger();
monitor = log4js.getLogger("monitorLogs");
//USAGE
//logger.debug("text");
//monitor.info('info');
//errLogger.error("some error");
}
process.on('uncaughtException', function (err) { process.on('uncaughtException', function (err) {
if(errLogger)
{
errLogger.error('uncaughtException:', err.message) errLogger.error('uncaughtException:', err.message)
errLogger.error(err.stack); errLogger.error(err.stack);
}
//TODO //TODO
//send to service //send to service
@ -127,13 +87,9 @@ const nosqlBackup = NOSQL('/backup/tbdata');
exports.install = function(instance) { exports.install = function(instance) {
var broker; var client;
var opts; var opts;
var brokerready = false; var clientReady = false;
instance.on('options', loadSettings);
mqtt = require('mqtt');
// wsmqtt status for notification purposes on projects.worksys.io database // wsmqtt status for notification purposes on projects.worksys.io database
let wsmqttName = null; let wsmqttName = null;
@ -149,14 +105,21 @@ exports.install = function(instance) {
function sendWsStatus() function sendWsStatus()
{ {
instance.send(instanceSendTo.services, {[wsmqttName]: wsmqtt_status}); instance.send(SEND_TO.services, {[wsmqttName]: wsmqtt_status});
} }
sendWsStatusVar = setInterval(sendWsStatus, 180000);
function main()
{
if(!FLOW.dbLoaded) return;
loadSettings();
clearInterval(sendWsStatus);
sendWsStatusVar = setInterval(sendWsStatus, 180000);
}
//set opts according to db settings //set opts according to db settings
async function loadSettings() function loadSettings()
{ {
if(instance.options.host !== "") if(instance.options.host !== "")
@ -179,21 +142,17 @@ exports.install = function(instance) {
else else
{ {
const dbSettings = TABLE("settings"); const SETTINGS = FLOW.GLOBALS.settings;
let responseSettings = await promisifyBuilder(dbSettings.find()); backup_on_failure = SETTINGS.backup_on_failure;
backup_on_failure = responseSettings[0]["backup_on_failure"];
saveTelemetryOnError = backup_on_failure; saveTelemetryOnError = backup_on_failure;
restore_from_backup = responseSettings[0]["restore_from_backup"]; restore_from_backup = SETTINGS.restore_from_backup;
restore_backup_wait = responseSettings[0]["restore_backup_wait"]; restore_backup_wait = SETTINGS.restore_backup_wait;
let mqtt_host = responseSettings[0]["mqtt_host"]; let mqtt_host = SETTINGS.mqtt_host;
let mqtt_clientid = responseSettings[0]["mqtt_clientid"]; let mqtt_clientid = SETTINGS.mqtt_clientid;
let mqtt_username = responseSettings[0]["mqtt_username"]; let mqtt_username = SETTINGS.mqtt_username;
let mqtt_port = responseSettings[0]["mqtt_port"]; let mqtt_port = SETTINGS.mqtt_port;
console.log("wsmqttpublich -> loadSettings from db", responseSettings[0]);
opts = { opts = {
host: mqtt_host, host: mqtt_host,
@ -216,27 +175,23 @@ exports.install = function(instance) {
var url = "mqtt://" + opts.host + ":" + opts.port; var url = "mqtt://" + opts.host + ":" + opts.port;
console.log("MQTT URL: ", url); console.log("MQTT URL: ", url);
broker = mqtt.connect(url, opts); client = mqtt.connect(url, opts);
broker.on('connect', function() { client.on('connect', function() {
instance.status("Connected", "green"); instance.status("Connected", "green");
monitor.info("MQTT broker connected"); monitor.info("MQTT client connected");
sendBrokerError = true; sendClientError = true;
clientReady = true;
brokerready = true;
FLOW.OMS_brokerready = brokerready;
wsmqtt_status = 'connected'; wsmqtt_status = 'connected';
}); });
broker.on('reconnect', function() { client.on('reconnect', function() {
instance.status("Reconnecting", "yellow"); instance.status("Reconnecting", "yellow");
brokerready = false; clientReady = false;
FLOW.OMS_brokerready = brokerready;
}); });
broker.on('message', function(topic, message) { client.on('message', function(topic, message) {
// message is type of buffer // message is type of buffer
message = message.toString(); message = message.toString();
if (message[0] === '{') { if (message[0] === '{') {
@ -244,50 +199,53 @@ exports.install = function(instance) {
message = JSON.parse(message); message = JSON.parse(message);
if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) { if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
broker.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1}); client.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1});
instance.send(instanceSendTo.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}}); instance.send(SEND_TO.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}});
} }
}, () => instance.debug('MQTT: Error parsing data', message)); }, () => instance.debug('MQTT: Error parsing data', message));
} }
instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message }); instance.send(SEND_TO.rpcCall, {"topic":topic, "content":message });
}); });
broker.on('close', function(err) { client.on('close', function(err) {
brokerready = false; clientReady = false;
FLOW.OMS_brokerready = brokerready;
wsmqtt_status = 'disconnected'; wsmqtt_status = 'disconnected';
if (err && err.toString().indexOf('Error')) { if (err && err.toString().indexOf('Error')) {
instance.status("Err: "+err.code, "red"); instance.status("Err: "+err.code, "red");
instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts }); instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !", "error":err, "opt":opts });
} else { } else {
instance.status("Disconnected", "red"); instance.status("Disconnected", "red");
instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts }); instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !", "error":err, "opt":opts });
} }
broker.reconnect(); client.reconnect();
}); });
broker.on('error', function(err) { client.on('error', function(err) {
instance.status("Err: "+ err.code, "red"); instance.status("Err: "+ err.code, "red");
instance.send(instanceSendTo.debug, {"message":"Broker ERROR signal received !", "error":err, "opt":opts }); instance.send(SEND_TO.debug, {"message":"Client ERROR signal received !", "error":err, "opt":opts });
if(sendBrokerError) { if(sendClientError) {
monitor.info('MQTT broker error', err); monitor.info('MQTT client error', err);
sendBrokerError = false; sendClientError = false;
} }
brokerready = false; clientReady = false;
FLOW.OMS_brokerready = brokerready;
wsmqtt_status = 'disconnected'; wsmqtt_status = 'disconnected';
}); });
} }
instance.on('data', function(data) {
if (brokerready) instance.on("0", _ => {
main();
})
instance.on('1', function(data) {
if(clientReady)
{ {
//do we have some data in backup file? //do we have some data in backup file?
//if any, process data from database //if any, process data from database
@ -296,13 +254,14 @@ exports.install = function(instance) {
//read telemetry data and send back to server //read telemetry data and send back to server
if(!processingData) processDataFromDatabase(); if(!processingData) processDataFromDatabase();
} }
} }
if (brokerready) if(clientReady)
{ {
let stringifiedJson = JSON.stringify(data.data); let stringifiedJson = JSON.stringify(data.data);
broker.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1}); client.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1});
instance.send(3, stringifiedJson);
//backup telemetry //backup telemetry
if(createTelemetryBackup) if(createTelemetryBackup)
@ -327,8 +286,8 @@ exports.install = function(instance) {
else else
{ {
if(logger) logger.debug("Broker unavailable. Data not sent !", JSON.stringify(data.data)); //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
instance.send(instanceSendTo.debug, {"message":"Broker unavailable. Data not sent !", "data": data.data }); instance.send(SEND_TO.debug, {"message":"Client unavailable. Data not sent !", "data": data.data });
if(saveTelemetryOnError) if(saveTelemetryOnError)
{ {
@ -345,8 +304,8 @@ exports.install = function(instance) {
instance.close = function(done) { instance.close = function(done) {
if (brokerready){ if(clientReady){
broker.end(); client.end();
clearInterval(sendWsStatusVar); clearInterval(sendWsStatusVar);
} }
}; };
@ -443,10 +402,7 @@ exports.install = function(instance) {
const processDataFromDatabase = async () => { const processDataFromDatabase = async () => {
if(restore_from_backup <= 0) if(restore_from_backup <= 0) return;
{
return;
}
//calculate diff //calculate diff
const now = new Date(); const now = new Date();
@ -478,7 +434,7 @@ exports.install = function(instance) {
for(let i = 0; i < records.length; i++) for(let i = 0; i < records.length; i++)
{ {
if (brokerready) { if(clientReady) {
let item = records[i]; let item = records[i];
let id = item.id; let id = item.id;
@ -493,7 +449,8 @@ exports.install = function(instance) {
delete o.id; delete o.id;
let message = JSON.stringify(o); let message = JSON.stringify(o);
broker.publish("v1/gateway/telemetry", message, {qos:1}); client.publish("v1/gateway/telemetry", message, {qos:1});
instance.send(3, message);
//remove from database //remove from database
await promisifyBuilder(nosql.remove().where("id", id)); await promisifyBuilder(nosql.remove().where("id", id));
@ -533,8 +490,6 @@ exports.install = function(instance) {
} }
loadSettings(); instance.on('options', main);
//instance.on('options', instance.reconfigure);
//instance.reconfigure(); //instance.reconfigure();
}; };