-
-
Hostname or IP address (if not empty - setting will override db setting)
-
+
+
+
Hostname or IP address (if not empty - setting will override db setting)
+
@@ -27,16 +27,14 @@ exports.html = `
`;
-
-
const { promisifyBuilder } = require('./helper/db_helper');
const fs = require('fs');
const mqtt = require('mqtt');
const nosql = NOSQL('tbdatacloud');
const SEND_TO = {
- debug: 0,
- rpcCall: 1,
+ debug: 0,
+ rpcCall: 1,
}
//CONFIG
@@ -56,319 +54,295 @@ 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;
-
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;
- if(!o.topic) o.topic = FLOW.GLOBALS.settings.cloud_topic;
-
- opts = {
- host: o.host,
- port: o.port,
- clientId: o.clientid,
- username: o.username,
- rejectUnauthorized: false,
- resubscribe: false
- };
-
- console.log("wsmqttpublich -> loadSettings from instance.options",o);
-
- 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() {
- 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() {
- clientReady = false;
-
- instance.status("Disconnected", "red");
- instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !"});
- });
-
- client.on('error', function(err) {
- instance.status("Err: "+ err.code, "red");
- instance.send(SEND_TO.debug, {"message":"Client ERROR signal received !", "error":err, "opt":opts });
- if(sendClientError) {
- 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();
- }
-
- let stringifiedJson = JSON.stringify(data.data)
- client.publish(`${o.topic}_forward`, stringifiedJson, {qos: 1});
- }
- else
- {
- //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
- instance.send(SEND_TO.debug, {"message":"Client unavailable. Data not sent !", "data": data.data });
-
- if(saveTelemetryOnError)
- {
- //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
- makeBackupFromDbFile();
-
- //write to tb
- data.data.id = UID();
- nosql.insert(data.data);
- }
- }
- });
-
- instance.on("1", _ => {
- main();
- })
-
- 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 {
+ 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;
+ if (!o.topic) o.topic = FLOW.GLOBALS.settings.cloud_topic;
+
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ username: o.username,
+ rejectUnauthorized: false,
+ resubscribe: false
+ };
+
+ console.log("wsmqttpublich -> loadSettings from instance.options", o);
+
+ 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() {
+ instance.status("Reconnecting", "yellow");
+ clientReady = false;
+ });
+
+ client.on('message', function(topic, message) {
+ // message is type of buffer
+ message = message.toString();
+ if (message[0] === '{') {
+
+
+ try {
+ 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 } });
+ }
+ } catch (e) { instance.debug('MQTT: Error parsing data', message) }
+
+ instance.send(SEND_TO.rpcCall, { "topic": o.topic, "content": message });
+ }
+ });
+
+ client.on('close', function() {
+ clientReady = false;
+
+ instance.status("Disconnected", "red");
+ instance.send(SEND_TO.debug, { "message": "Client CLOSE signal received !" });
+ });
- let message = JSON.parse(JSON.stringify(item));
- delete message.id;
- client.publish(`${o.topic}_forward`, JSON.stringify(message), {qos:1});
-
- //remove from database
- await promisifyBuilder(nosql.remove().where("id", id));
+ 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;
+ });
- } catch(error) {
- //process error
- console.log("processDataFromDatabase", error);
- }
+ }
- }
-
- }
- else
- {
- processingData = false;
- return;
- }
- }
- if(records.length > 0)
- {
- //clean backup file
- if(counter > 0) nosql.clean();
- }
+ instance.on('0', function(data) {
- //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);
+ 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();
+ }
+
+ let stringifiedJson = JSON.stringify(data.data)
+ client.publish(`${o.topic}_forward`, stringifiedJson, { qos: 1 });
+ }
+ else {
+ //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
+ instance.send(SEND_TO.debug, { "message": "Client unavailable. Data not sent !", "data": data.data });
+
+ if (saveTelemetryOnError) {
+ //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
+ makeBackupFromDbFile();
+
+ //write to tb
+ data.data.id = UID();
+ nosql.insert(data.data);
+ }
+ }
+ });
+
+ instance.on("1", _ => {
+ main();
+ })
+
+ 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 message = JSON.parse(JSON.stringify(item));
+ delete message.id;
+ client.publish(`${o.topic}_forward`, JSON.stringify(message), { qos: 1 });
+
+ //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);
};
diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js
index 07e12c6..d5f0842 100644
--- a/flow/cmd_manager.js
+++ b/flow/cmd_manager.js
@@ -30,2769 +30,2765 @@ exports.readme = `Manager for CMD calls`;
exports.install = function(instance) {
- const SerialPort = require('serialport');
- const { exec } = require('child_process');
- const { crc16 } = require('easy-crc');
- const { runSyncExec, writeData } = require('./helper/serialport_helper');
- const { bytesToInt, longToByteArray, addZeroBefore } = require('./helper/utils');
- const bitwise = require('bitwise');
-
- var SunCalc = require('./helper/suncalc');
- const DataToTbHandler = require('./helper/DataToTbHandler');
- const errorHandler = require('./helper/ErrorToServiceHandler');
- const { sendNotification } = require('./helper/notification_reporter');
- const process = require('process');
- const { errLogger, logger, monitor } = require('./helper/logger');
-
- //for accelerometer purposes
- const { naklony } = require("../databases/accelerometer_db");
-
- const dbNodes = TABLE("nodes");
- const dbRelays = TABLE("relays");
-
- let GLOBALS;
- let SETTINGS;
- let rsPort;
- let tbHandler;
-
- // runTasks intervals
- const SHORT_INTERVAL = 30;
- const LONG_INTERVAL = 300;
-
- //send data to following instances:
- const SEND_TO = {
- debug: 0,
- tb: 1,
- http_response: 2,
- dido_controller: 3,
- infoSender: 4
- }
-
- const PRIORITY_TYPES = {
- terminal: 0,
- fw_detection: 1,//reserved only for FW detection - SETTINGS.masterNodeIsResponding
- high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform)
- relay_profile: 3,
- node_broadcast: 4,
- node_profile: 5,
- node_cmd: 6
- }
-
- const TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION = 600000; // 10 minutes
-
- //list of command calls to process. Processing in runTasks function
- let tasks = [];
-
- let interval = null;//timeout for procesing tasks
- let customTasksInterval = null; // interval for reportEdgeDateTimeAndNumberOfLuminaires();
- let setCorrectTime = null; // interval for setting a correct edgeTime
- let sendNodeReadout = null; // interval for sending agregate data from node
-
- let refFlowdataObj = {};
-
- //load from settings
- let latitude = 48.70826502;//48.682255758;
- let longitude = 17.28455203;//17.278910807;
-
- const gmtOffset = 0;
-
- //ak nie je nastaveny
- //https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
- //https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
-
- //priorities for registers
- let priorities = [];
-
- let minutes = 1;
- priorities["1"] = minutes; // dimming
- priorities["76"] = minutes; // power
-
- minutes = 5;
- priorities["75"] = minutes; // current
- priorities["79"] = minutes; // energy
- priorities["87"] = minutes; // aktualny cas
- //priorities["84"] = minutes;
-
- minutes = 10;
- priorities["74"] = minutes; // voltage
- priorities["77"] = minutes; // power factor
- priorities["78"] = minutes; // frequency
-
- minutes = 60;
- priorities["0"] = minutes; // statecode
- priorities["6"] = minutes; // dusk
- priorities["7"] = minutes; // dawn
- priorities["8"] = minutes; // profile
-
- minutes = 60 * 24;
- priorities["89"] = minutes; // verzia fw
- priorities["80"] = minutes; // lifetime
-
- //prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming)
- let listOfCommands = [0, 1, 6, 7, 8, 74, 75, 76, 77, 78, 79, 80, 87, 89];
-
- let rotary_switch_state;
- let lux_sensor;
- let state_of_breaker = {};//key is line, value is On/Off
- let disconnectedReport = {};//key is tbname, value true/false
-
- let relaysData;
- let nodesData;
-
- let sunCalcResult;
- let reportDuskDawn;
-
- //helper container for counting resolved group of commands (commands related to set profile)
- let cmdCounter = {};//key is node, value is counter
-
- //if sending of profile to node fails, we send notification and push node into set, so we do not send notification twice
- const nodeProfileSendFail = new Set();
-
- //we expect to get current temperature in Senica from senica-prod01
- let temperatureInSenica = null;
- let accelerometerInterval = null;
-
- //END OF VARIABLE SETTINGS
- //--------------------------------
-
-
- function main() {
- GLOBALS = FLOW.GLOBALS;
- SETTINGS = FLOW.GLOBALS.settings;
- relaysData = GLOBALS.relaysData;
- nodesData = GLOBALS.nodesData;
- latitude = GLOBALS.settings.latitude;
- longitude = GLOBALS.settings.longitude;
-
- tbHandler = new DataToTbHandler(SEND_TO.tb);
- tbHandler.setSender(exports.title);
-
- let now = new Date();
- console.log("Cmd-mngr installed", now.toLocaleString("sk-SK"));
-
- sunCalcResult = calculateDuskDawn();
-
- reportDuskDawn = {
- dusk_time: sunCalcResult.dusk_time,
- dawn_time: sunCalcResult.dawn_time,
- dusk_time_reported: undefined,
- dawn_time_reported: undefined
- };
+ const { SerialPort } = require('serialport');
+ const { exec } = require('child_process');
+ const { crc16 } = require('easy-crc');
+ const { runSyncExec, writeData } = require('./helper/serialport_helper');
+ const { bytesToInt, longToByteArray, addZeroBefore } = require('./helper/utils');
+ const bitwise = require('bitwise');
+
+ var SunCalc = require('./helper/suncalc');
+ const DataToTbHandler = require('./helper/DataToTbHandler');
+ const errorHandler = require('./helper/ErrorToServiceHandler');
+ const { sendNotification } = require('./helper/notification_reporter');
+ const process = require('process');
+ const { errLogger, logger, monitor } = require('./helper/logger');
+
+ //for accelerometer purposes
+ const { naklony } = require("../databases/accelerometer_db");
+
+ const dbNodes = TABLE("nodes");
+ const dbRelays = TABLE("relays");
+
+ let GLOBALS;
+ let SETTINGS;
+ let rsPort;
+ let tbHandler;
+
+ // runTasks intervals
+ const SHORT_INTERVAL = 30;
+ const LONG_INTERVAL = 300;
+
+ //send data to following instances:
+ const SEND_TO = {
+ debug: 0,
+ tb: 1,
+ http_response: 2,
+ dido_controller: 3,
+ infoSender: 4
+ }
+
+ const PRIORITY_TYPES = {
+ terminal: 0,
+ fw_detection: 1,//reserved only for FW detection - SETTINGS.masterNodeIsResponding
+ high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform)
+ relay_profile: 3,
+ node_broadcast: 4,
+ node_profile: 5,
+ node_cmd: 6
+ }
+
+ const TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION = 600000; // 10 minutes
+
+ //list of command calls to process. Processing in runTasks function
+ let tasks = [];
+
+ let interval = null;//timeout for procesing tasks
+ let customTasksInterval = null; // interval for reportEdgeDateTimeAndNumberOfLuminaires();
+ let setCorrectTime = null; // interval for setting a correct edgeTime
+ let sendNodeReadout = null; // interval for sending agregate data from node
+
+ let refFlowdataObj = {};
+
+ //load from settings
+ let latitude = 48.70826502;//48.682255758;
+ let longitude = 17.28455203;//17.278910807;
+
+ const gmtOffset = 0;
+
+ //ak nie je nastaveny
+ //https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
+ //https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
+
+ //priorities for registers
+ let priorities = [];
+
+ let minutes = 1;
+ priorities["1"] = minutes;
+ priorities["76"] = minutes;
+
+ // minutes = 5;
+ priorities["75"] = minutes;//current
+ priorities["79"] = minutes;//energy
+ priorities["87"] = minutes;//aktualny cas
+ //priorities["84"] = minutes;
+
+ // minutes = 10;
+ priorities["74"] = minutes;
+ priorities["77"] = minutes;
+ priorities["78"] = minutes;
+
+ // minutes = 60;
+ priorities["0"] = minutes;
+ priorities["6"] = minutes;
+ priorities["7"] = minutes;
+ priorities["8"] = minutes;
+
+ // minutes = 60 * 24;
+ priorities["89"] = minutes;
+ priorities["80"] = minutes;
+
+ //prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming)
+ let listOfCommands = [0, 1, 6, 7, 8, 74, 75, 76, 77, 78, 79, 80, 87, 89];
+
+ let rotary_switch_state;
+ let lux_sensor;
+ let state_of_breaker = {};//key is line, value is On/Off
+ let disconnectedReport = {};//key is tbname, value true/false
+
+ let relaysData;
+ let nodesData;
+
+ let sunCalcResult;
+ let reportDuskDawn;
+
+ //helper container for counting resolved group of commands (commands related to set profile)
+ let cmdCounter = {};//key is node, value is counter
+
+ //if sending of profile to node fails, we send notification and push node into set, so we do not send notification twice
+ const nodeProfileSendFail = new Set();
+
+ //we expect to get current temperature in Senica from senica-prod01
+ let temperatureInSenica = null;
+ let accelerometerInterval = null;
+
+ //END OF VARIABLE SETTINGS
+ //--------------------------------
+
+
+ function main() {
+ GLOBALS = FLOW.GLOBALS;
+ SETTINGS = FLOW.GLOBALS.settings;
+ relaysData = GLOBALS.relaysData;
+ nodesData = GLOBALS.nodesData;
+ latitude = GLOBALS.settings.latitude;
+ longitude = GLOBALS.settings.longitude;
+
+ tbHandler = new DataToTbHandler(SEND_TO.tb);
+ tbHandler.setSender(exports.title);
+
+ let now = new Date();
+ console.log("CMD Manager installed", now.toLocaleString("sk-SK"));
+
+ sunCalcResult = calculateDuskDawn();
+
+ reportDuskDawn = {
+ dusk_time: sunCalcResult.dusk_time,
+ dawn_time: sunCalcResult.dawn_time,
+ dusk_time_reported: undefined,
+ dawn_time_reported: undefined
+ };
- handleRsPort();
+ handleRsPort();
- customTasksInterval = setInterval(function() {
- reportEdgeDateTimeAndNumberOfLuminaires();
- }, 120000);
- reportEdgeDateTimeAndNumberOfLuminaires();
+ customTasksInterval = setInterval(function() {
+ reportEdgeDateTimeAndNumberOfLuminaires();
+ }, 120000);
+ reportEdgeDateTimeAndNumberOfLuminaires();
- setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
- setCorrectPlcTimeOnceADay();
+ setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
+ setCorrectPlcTimeOnceADay();
- sendNodeReadout = setInterval(sendNodesData, 150000);
- accelerometerInterval = setInterval(accelerometerData, 60000 * 30); //30 min
- }
-
-
- function cmdCounterResolve(address) {
- if (cmdCounter.hasOwnProperty(address)) {
- cmdCounter[address] = cmdCounter[address] - 1;
-
- let result = cmdCounter[address];
- if (result == 0) delete cmdCounter[address];
- return result;
- }
- return -1;
- }
-
-
- function getParams(priority) {
- let params = {};
-
- //core rpc values
- params.address = 0;//if(recipient === 0) address = 0;
- params.byte1 = 0;//msb, podla dokumentacie data3
- params.byte2 = 0;//podla dokumentacie data2
- params.byte3 = 0;//podla dokumentacie data1
- params.byte4 = 0;//lsb, podla dokumentacie data0
- params.recipient = 0;//0: Master, 1: Slave, 2: Broadcast
- params.register = -1;//register number
- params.rw = 0;//0: read, 1: write
-
- //other values
- //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles"
- //params.tbname = tbname;
- params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority
- params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed
- if (priority != undefined) {
- params.timestamp = priority;
- params.priority = priority;
- }
+ sendNodeReadout = setInterval(sendNodesData, 150000);
+ accelerometerInterval = setInterval(accelerometerData, 60000 * 30); //30 min
+ }
+
+
+ function cmdCounterResolve(address) {
+ if (cmdCounter.hasOwnProperty(address)) {
+ cmdCounter[address] = cmdCounter[address] - 1;
+
+ let result = cmdCounter[address];
+ if (result == 0) delete cmdCounter[address];
+ return result;
+ }
+ return -1;
+ }
+
+
+ function getParams(priority) {
+ let params = {};
+
+ //core rpc values
+ params.address = 0;//if(recipient === 0) address = 0;
+ params.byte1 = 0;//msb, podla dokumentacie data3
+ params.byte2 = 0;//podla dokumentacie data2
+ params.byte3 = 0;//podla dokumentacie data1
+ params.byte4 = 0;//lsb, podla dokumentacie data0
+ params.recipient = 0;//0: Master, 1: Slave, 2: Broadcast
+ params.register = -1;//register number
+ params.rw = 0;//0: read, 1: write
+
+ //other values
+ //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles"
+ //params.tbname = tbname;
+ params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority
+ params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed
+ if (priority != undefined) {
+ params.timestamp = priority;
+ params.priority = priority;
+ }
- params.addMinutesToTimestamp = 0;//repeat task if value is > 0
- // if node regular readout does not respond, we repeat request
- params.repeatCounter = 0;
- //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint"
- //params.info = "";
- //params.debug = true; // will console.log params in writeData response
-
- return params;
- }
-
-
- //nastav profil nodu
- function processNodeProfile(node) {
- if (rotary_switch_state != "Automatic") {
- logger.debug("unable to process profile for node", node, "rotary_switch_state != Automatic");
- return;
- }
-
- let nodeObj = nodesData[node];
- let line = nodeObj.line;
-
- if (relaysData[line].contactor == 0) {
- logger.debug("line line is off", line, node);
- return;
- }
-
- if (nodeObj.processed == 1) {
- //logger.debug("node was already processed", node);
- return;
- }
-
- let nodeProfile = nodeObj.profile;
- logger.debug("processNodeProfile: start - set profile for ", node, nodeProfile);
- if (nodeProfile) {
-
- try {
- nodeProfile = JSON.parse(nodeProfile);
- } catch (error) {
- logger.debug("Cmd-mngr: Error parsing node profile", error);
- }
-
- }
-
- logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile);
-
- let timestamp = PRIORITY_TYPES.node_cmd;
-
- removeTask({ type: "set_node_profile", address: node });
-
- if (nodeProfile === "") {
- //vypneme profil nodu, posleme cmd
- //Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
- //Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
-
- logger.debug("turn off profile");
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte4 = 96;
- params.recipient = 1;
- params.register = 8;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = 'turn off/reset node profile';
-
- cmdCounter[node] = 1;
-
- tasks.push(params);
- }
- else {
- let tasksProfile = [];
-
- //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte4 = 96;
- params.recipient = 1;
- params.register = 8;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = 'turn off node profile';
-
- tasksProfile.push(params);
-
- timestamp++;
-
- logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node);
-
- //TS1 Time point a TS1 Time Point Levels
- let register = 9;
- for (let i = 0; i < nodeProfile.intervals.length; i++) {
- let obj = nodeProfile.intervals[i];
- //let timePoint = obj.time_point;
- let dim_value = obj.value;
-
-
- //Reg 9 až Reg 40
-
- /*
- Samotný profil sa zapisuje do max. 16 párov – časový bod a úroveň.
- Prázdny profil je vtedy keď časový bod obsahuje hodnotu 0xFFFFFFFF (táto hodnota sa zapíše do registrov keď sa aktivuje reset profilu do registru 8).
- Páry sa prechádzajú časovo zoradené takže teoreticky je jedno v akom poradí sa zapisujú ale je lepšie ich zapisovať v chronologickom poradí od 13:00.
- Časový bod má formát:
- Byte 3: hodiny Byte 2: minúty Byte 1: sekundy Byte 0 – rezervované
- Register úrovne má rovnaký formát ako dimming register (Reg 1).
- */
-
- let start_time = obj.start_time;
- let t = start_time.split(":");
- //if(timePoint != undefined) t = timePoint.split(":");
- //else t = [0,0];
-
- logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node);
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte1 = parseInt(t[0]);//hh
- params.byte2 = parseInt(t[1]);//mm
- params.recipient = 1;
- params.register = register;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'TS1 Time point ' + (i + 1);
-
- tasksProfile.push(params);
-
- register++;
- timestamp++;
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte4 = parseInt(dim_value) + 128;//
- params.recipient = 1;
- params.register = register;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'TS1 Time point Levels ' + (i + 1);
-
- tasksProfile.push(params);
-
- register++;
- timestamp++;
- }
-
- //Threshold lux level for DUSK/DAWN
- {
-
- logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node);
-
- let params = getParams();
- params.type = "set_node_profile";
- params.address = node;
- params.register = 96;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = "Threshold lux level for DUSK/DAWN";
-
- if (nodeProfile.dusk_lux_sensor) {
- let v = nodeProfile.dusk_lux_sensor_value;
- let ba = longToByteArray(v);
-
- params.byte1 = ba[1];//msb
- params.byte2 = ba[0];
- }
-
- if (nodeProfile.dawn_lux_sensor) {
- let v = nodeProfile.dawn_lux_sensor_value;
- let ba = longToByteArray(v);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- }
-
- tasksProfile.push(params);
- timestamp++;
-
- }
-
- //DUSK/DAWN max. adjust period
- {
-
- logger.debug("processNodeProfile: DUSK/DAWN max. adjust period", node);
-
- let params = getParams();
- params.type = "set_node_profile";
- params.address = node;
- params.register = 97;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = "DUSK/DAWN max. adjust period";
-
- if (nodeProfile.astro_clock) {
- let v = nodeProfile.dusk_lux_sensor_time_window;
- let ba = longToByteArray(v);
-
- params.byte1 = ba[1];//msb
- params.byte2 = ba[0];
- }
-
- if (nodeProfile.astro_clock) {
- let v = nodeProfile.dawn_lux_sensor_time_window;
- let ba = longToByteArray(v);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- }
-
- tasksProfile.push(params);
- timestamp++;
-
- }
-
- //Static offset
- {
-
- //Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
- //Bity 0 – 6: hodnota v minútach
- //Bit 7: znamienko (1 – mínus)
-
- logger.debug("processNodeProfile: Static offset", node);
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 98;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = "Static offset";
-
- if (nodeProfile.astro_clock) {
- let dusk_astro_clock_offset = parseInt(nodeProfile.dusk_astro_clock_offset);
- let dawn_astro_clock_offset = parseInt(nodeProfile.dawn_astro_clock_offset);
-
- if (dusk_astro_clock_offset < 0) {
- params.byte3 = (dusk_astro_clock_offset * -1) + 128;
- }
- else {
- params.byte3 = dusk_astro_clock_offset;
- }
-
- if (dawn_astro_clock_offset < 0) {
- params.byte4 = (dawn_astro_clock_offset * -1) + 128;
- }
- else {
- params.byte4 = dawn_astro_clock_offset;
- }
- }
-
- tasksProfile.push(params);
- timestamp++;
- }
-
- logger.debug("Time schedule settings - turn on", node);
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 8;
- params.recipient = 1;
- params.rw = 1;//write
-
- //Time schedule settings
- let bits = [];
-
- //Byte 0 (LSB):
- //Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
- bits.push(1);
- //Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
- bits.push(0);
- bits.push(0);
- bits.push(0);
- if (nodeProfile.astro_clock == true) {
- //Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
- bits.push(0);
-
- //Bity 6-7 - zatiaľ nepoužité
- bits.push(0);
- bits.push(0);
-
- params.byte4 = bitwise.byte.write(bits.reverse());
-
- //Byte 2 – nastavenie pre lux senzor:
- bits = [];
-
- //Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
- if (nodeProfile.dusk_lux_sensor == true)//sumrak
- {
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
- if (nodeProfile.dawn_lux_sensor == true)//usvit
- {
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
- bits.push(0);//zatial neimplementovane
-
- //Bit 3 – 7 - nepoužité
- bits.push(0);
- bits.push(0);
- bits.push(0);
- bits.push(0);
- bits.push(0);
-
- params.byte2 = bitwise.byte.write(bits.reverse());
- params.timestamp = timestamp;
- params.info = "Time schedule settings - turn on";
-
- tasksProfile.push(params);
-
- //zaver
- cmdCounter[node] = tasksProfile.length;
-
- //tasks.push(tasksProfile);
- tasks = tasks.concat(tasksProfile);
-
- }
-
- logger.debug("finished set profile for ", node);
-
- console.log("proces profile finished *********************")
- }
-
-
- function cleanUpRefFlowdataObj() {
- let now = new Date();
- let timestamp = now.getTime();
+ params.addMinutesToTimestamp = 0;//repeat task if value is > 0
+ //if node regular readout does not respond, we repeat request
+ params.repeatCounter = 0;
+ //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint"
+ //params.info = "";
+ //params.debug = true; // will console.log params in writeData response
+
+ return params;
+ }
+
+
+ //nastav profil nodu
+ function processNodeProfile(node) {
+ if (rotary_switch_state != "Automatic") {
+ logger.debug("unable to process profile for node", node, "rotary_switch_state != Automatic");
+ return;
+ }
+
+ let nodeObj = nodesData[node];
+ let line = nodeObj.line;
+
+ if (relaysData[line].contactor == 0) {
+ logger.debug("line line is off", line, node);
+ return;
+ }
+
+ if (nodeObj.processed == 1) {
+ //logger.debug("node was already processed", node);
+ return;
+ }
+
+ let nodeProfile = nodeObj.profile;
+ logger.debug("processNodeProfile: start - set profile for ", node, nodeProfile);
+ if (nodeProfile) {
+
+ try {
+ nodeProfile = JSON.parse(nodeProfile);
+ } catch (error) {
+ logger.debug("Cmd_manager - Error parsing node profile", error);
+ }
+
+ }
+
+ logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile);
+
+ let timestamp = PRIORITY_TYPES.node_cmd;
+
+ removeTask({ type: "set_node_profile", address: node });
+
+ if (nodeProfile === "") {
+ //vypneme profil nodu, posleme cmd
+ //Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
+ //Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
+
+ logger.debug("turn off profile");
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte4 = 96;
+ params.recipient = 1;
+ params.register = 8;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.info = 'turn off/reset node profile';
+
+ cmdCounter[node] = 1;
+
+ tasks.push(params);
+ }
+ else {
+ let tasksProfile = [];
+
+ //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte4 = 96;
+ params.recipient = 1;
+ params.register = 8;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.info = 'turn off node profile';
+
+ tasksProfile.push(params);
+
+ timestamp++;
+
+ logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node);
+
+ //TS1 Time point a TS1 Time Point Levels
+ let register = 9;
+ for (let i = 0; i < nodeProfile.intervals.length; i++) {
+ let obj = nodeProfile.intervals[i];
+ //let timePoint = obj.time_point;
+ let dim_value = obj.value;
+
+
+ //Reg 9 až Reg 40
+
+ /*
+ Samotný profil sa zapisuje do max. 16 párov – časový bod a úroveň.
+ Prázdny profil je vtedy keď časový bod obsahuje hodnotu 0xFFFFFFFF (táto hodnota sa zapíše do registrov keď sa aktivuje reset profilu do registru 8).
+ Páry sa prechádzajú časovo zoradené takže teoreticky je jedno v akom poradí sa zapisujú ale je lepšie ich zapisovať v chronologickom poradí od 13:00.
+ Časový bod má formát:
+ Byte 3: hodiny Byte 2: minúty Byte 1: sekundy Byte 0 – rezervované
+ Register úrovne má rovnaký formát ako dimming register (Reg 1).
+ */
+
+ let start_time = obj.start_time;
+ let t = start_time.split(":");
+ //if(timePoint != undefined) t = timePoint.split(":");
+ //else t = [0,0];
+
+ logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node);
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = parseInt(t[0]);//hh
+ params.byte2 = parseInt(t[1]);//mm
+ params.recipient = 1;
+ params.register = register;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'TS1 Time point ' + (i + 1);
+
+ tasksProfile.push(params);
+
+ register++;
+ timestamp++;
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte4 = parseInt(dim_value) + 128;//
+ params.recipient = 1;
+ params.register = register;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'TS1 Time point Levels ' + (i + 1);
+
+ tasksProfile.push(params);
+
+ register++;
+ timestamp++;
+ }
+
+ //Threshold lux level for DUSK/DAWN
+ {
+
+ logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node);
+
+ let params = getParams();
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 96;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.info = "Threshold lux level for DUSK/DAWN";
+
+ if (nodeProfile.dusk_lux_sensor) {
+ let v = nodeProfile.dusk_lux_sensor_value;
+ let ba = longToByteArray(v);
+
+ params.byte1 = ba[1];//msb
+ params.byte2 = ba[0];
+ }
+
+ if (nodeProfile.dawn_lux_sensor) {
+ let v = nodeProfile.dawn_lux_sensor_value;
+ let ba = longToByteArray(v);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+
+ }
+
+ //DUSK/DAWN max. adjust period
+ {
+
+ logger.debug("processNodeProfile: DUSK/DAWN max. adjust period", node);
+
+ let params = getParams();
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 97;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.info = "DUSK/DAWN max. adjust period";
+
+ if (nodeProfile.astro_clock) {
+ let v = nodeProfile.dusk_lux_sensor_time_window;
+ let ba = longToByteArray(v);
+
+ params.byte1 = ba[1];//msb
+ params.byte2 = ba[0];
+ }
+
+ if (nodeProfile.astro_clock) {
+ let v = nodeProfile.dawn_lux_sensor_time_window;
+ let ba = longToByteArray(v);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+
+ }
+
+ //Static offset
+ {
+
+ //Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
+ //Bity 0 – 6: hodnota v minútach
+ //Bit 7: znamienko (1 – mínus)
+
+ logger.debug("processNodeProfile: Static offset", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 98;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.info = "Static offset";
+
+ if (nodeProfile.astro_clock) {
+ let dusk_astro_clock_offset = parseInt(nodeProfile.dusk_astro_clock_offset);
+ let dawn_astro_clock_offset = parseInt(nodeProfile.dawn_astro_clock_offset);
+
+ if (dusk_astro_clock_offset < 0) {
+ params.byte3 = (dusk_astro_clock_offset * -1) + 128;
+ }
+ else {
+ params.byte3 = dusk_astro_clock_offset;
+ }
+
+ if (dawn_astro_clock_offset < 0) {
+ params.byte4 = (dawn_astro_clock_offset * -1) + 128;
+ }
+ else {
+ params.byte4 = dawn_astro_clock_offset;
+ }
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+ }
+
+ logger.debug("Time schedule settings - turn on", node);
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 8;
+ params.recipient = 1;
+ params.rw = 1;//write
+
+ //Time schedule settings
+ let bits = [];
+
+ //Byte 0 (LSB):
+ //Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
+ bits.push(1);
+ //Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ if (nodeProfile.astro_clock == true) {
+ //Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
+ bits.push(0);
+
+ //Bity 6-7 - zatiaľ nepoužité
+ bits.push(0);
+ bits.push(0);
+
+ params.byte4 = bitwise.byte.write(bits.reverse());
+
+ //Byte 2 – nastavenie pre lux senzor:
+ bits = [];
+
+ //Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
+ if (nodeProfile.dusk_lux_sensor == true)//sumrak
+ {
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
+ if (nodeProfile.dawn_lux_sensor == true)//usvit
+ {
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
+ bits.push(0);//zatial neimplementovane
+
+ //Bit 3 – 7 - nepoužité
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+
+ params.byte2 = bitwise.byte.write(bits.reverse());
+ params.timestamp = timestamp;
+ params.info = "Time schedule settings - turn on";
+
+ tasksProfile.push(params);
+
+ //zaver
+ cmdCounter[node] = tasksProfile.length;
+
+ //tasks.push(tasksProfile);
+ tasks = tasks.concat(tasksProfile);
+
+ }
+
+ logger.debug("finished set profile for ", node);
+
+ console.log("proces profile finished *********************")
+ }
+
+
+ function cleanUpRefFlowdataObj() {
+ let now = new Date();
+ let timestamp = now.getTime();
- //clear old refFlowdata references
- let keys = Object.keys(refFlowdataObj);
- for (let i = 0; i < keys.length; i++) {
- let timestampKey = keys[i];
+ //clear old refFlowdata references
+ let keys = Object.keys(refFlowdataObj);
+ for (let i = 0; i < keys.length; i++) {
+ let timestampKey = keys[i];
- if ((timestamp - timestampKey) > 60 * 1000) {
- console.log("cleanUpRefFlowdataObj delete", timestampKey);
- delete refFlowdataObj[timestampKey];
- }
- }
- }
+ if ((timestamp - timestampKey) > 60 * 1000) {
+ console.log("cleanUpRefFlowdataObj delete", timestampKey);
+ delete refFlowdataObj[timestampKey];
+ }
+ }
+ }
- function removeTask(obj) {
- let keys = Object.keys(obj);
- tasks = tasks.filter((task) => {
+ function removeTask(obj) {
+ let keys = Object.keys(obj);
+ tasks = tasks.filter((task) => {
- let counter = 0;
- for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
- if (task.hasOwnProperty(key) && obj.hasOwnProperty(key)) {
- if (task[key] == obj[key]) counter++;
- }
- }
+ let counter = 0;
+ for (let i = 0; i < keys.length; i++) {
+ let key = keys[i];
+ if (task.hasOwnProperty(key) && obj.hasOwnProperty(key)) {
+ if (task[key] == obj[key]) counter++;
+ }
+ }
- if (counter == keys.length) return false;
- return true;
- });
- }
+ if (counter == keys.length) return false;
+ return true;
+ });
+ }
- process.on('uncaughtException', function(err) {
- //TODO send to service
+ process.on('uncaughtException', function(err) {
+ //TODO send to service
- errLogger.error('uncaughtException:', err.message)
- errLogger.error(err.stack);
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
- errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
- //process.exit(1);
- })
+ errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
+ //process.exit(1);
+ })
- //te();//force error
+ //te();//force error
- function processAllNodeProfilesOnLine(line) {
- for (let k in nodesData) {
- if (line == nodesData[k].line) {
- let node = nodesData[k].node;
- let processed = nodesData[k].processed;
-
- if (!processed) processNodeProfile(node);
- //else logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`);
- }
- }
- }
-
-
- function loadRelaysData(line) {
- for (const [key, value] of Object.entries(relaysData)) {
- if (key == "0") continue;
- if (line != undefined) {
- //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData
- if (line != value.line) continue;
- }
-
- if (value.contactor == 1) processAllNodeProfilesOnLine(value.line);
- }
- }
-
-
- function reportOnlineNodeStatus(line) {
- //Po zapnutí línie broadcastovo aktualizovať predtým čas a o 3 sek neskor - status, brightness
-
- logger.debug("Cmd-mngr: ----->reportOnlineNodeStatus for line", line);
+ function processAllNodeProfilesOnLine(line) {
+ for (let k in nodesData) {
+ if (line == nodesData[k].line) {
+ let node = nodesData[k].node;
+ let processed = nodesData[k].processed;
+
+ if (!processed) processNodeProfile(node);
+ //else logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`);
+ }
+ }
+ }
+
+
+ function loadRelaysData(line) {
+ for (const [key, value] of Object.entries(relaysData)) {
+ if (key == "0") continue;
+ if (line != undefined) {
+ //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData
+ if (line != value.line) continue;
+ }
+
+ if (value.contactor == 1) processAllNodeProfilesOnLine(value.line);
+ }
+ }
+
+
+ function reportOnlineNodeStatus(line) {
+ //Po zapnutí línie broadcastovo aktualizovať predtým čas a o 3 sek neskor - status, brightness
+
+ logger.debug("Cmd-mngr: ----->reportOnlineNodeStatus for line", line);
- const d = new Date();
+ const d = new Date();
- // broadcast actual time
- let params = getParams();
- params.address = 0xffffffff;//Broadcast
- params.byte1 = d.getHours();
- params.byte2 = d.getMinutes();
- params.recipient = 2;//2 broadcast, address = 0
- params.register = 87;//Actual time
- params.rw = 1;//write
- params.type = "node-onetime-write";
- params.timestamp = d.getTime() + 30000;
- params.info = "run broadcast: Actual time";
- //params.debug = true;
+ // broadcast actual time
+ let params = getParams();
+ params.address = 0xffffffff;//Broadcast
+ params.byte1 = d.getHours();
+ params.byte2 = d.getMinutes();
+ params.recipient = 2;//2 broadcast, address = 0
+ params.register = 87;//Actual time
+ params.rw = 1;//write
+ params.type = "node-onetime-write";
+ params.timestamp = d.getTime() + 30000;
+ params.info = "run broadcast: Actual time";
+ //params.debug = true;
- tasks.push(params);
+ tasks.push(params);
- let sec = 3;
- setTimeout(function() {
- //Po zapnutí línie - spraviť hromadný refresh stavu práve zapnutých svietidiel
+ let sec = 3;
+ setTimeout(function() {
+ //Po zapnutí línie - spraviť hromadný refresh stavu práve zapnutých svietidiel
- let time = Date.now();
-
- for (let k in nodesData) {
+ let time = Date.now();
+
+ for (let k in nodesData) {
- //potrebujem nody k danej linii
- if (line == nodesData[k].line || line == undefined) {
+ //potrebujem nody k danej linii
+ if (line == nodesData[k].line || line == undefined) {
- let tbname = nodesData[k].tbname;
- let node = nodesData[k].node;
- let status = "NOK";
+ let tbname = nodesData[k].tbname;
+ let node = nodesData[k].node;
+ let status = "NOK";
- // if status of node was "OK" before switching it off, we set the node's time_of_last_communication on time, it was switched on again and send OK status to tb.
- if (nodesData[k].node_status_before_offline === true || nodesData[k].status === true) {
- status = "OK";
- nodesData[k].time_of_last_communication = time;
- }
+ // if status of node was "OK" before switching it off, we set the node's time_of_last_communication on time, it was switched on again and send OK status to tb.
+ if (nodesData[k].node_status_before_offline === true || nodesData[k].status === true) {
+ status = "OK";
+ nodesData[k].time_of_last_communication = time;
+ }
- nodesData[k].readout.status = status;
+ nodesData[k].readout.status = status;
- updateNodeStatus(k, status === "OK" ? true : false);
- if (nodesData[k].hasOwnProperty("node_status_before_offline")) delete nodesData[k].node_status_before_offline;
- sendTelemetry({ status: status }, tbname, time);
+ updateNodeStatus(k, status === "OK" ? true : false);
+ if (nodesData[k].hasOwnProperty("node_status_before_offline")) delete nodesData[k].node_status_before_offline;
+ sendTelemetry({ status: status }, tbname, time);
- //vyreportovanie dimming, current, input power pre liniu pre vsetky nody
- //Prud
- {
- let params = getParams();
+ //vyreportovanie dimming, current, input power pre liniu pre vsetky nody
+ //Prud
+ {
+ let params = getParams();
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 75;//prud
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = time + 4000;
- params.info = 'read current';
- //params.debug = true;
- tasks.push(params);
- }
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 75;//prud
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = time + 4000;
+ params.info = 'read current';
+ //params.debug = true;
+ tasks.push(params);
+ }
- //vykon
- {
- let params = getParams();
+ //vykon
+ {
+ let params = getParams();
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 76;//výkon
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = time + 4100;
- params.info = 'read power';
- //params.debug = true;
-
- tasks.push(params);
- }
- //dimming
- {
- let params = getParams();
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;//dimming
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = time + 4200;
- params.info = 'read dimming';
- //params.debug = true;
-
- tasks.push(params);
- }
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 76;//výkon
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = time + 4100;
+ params.info = 'read power';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+ //dimming
+ {
+ let params = getParams();
+
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;//dimming
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = time + 4200;
+ params.info = 'read dimming';
+ //params.debug = true;
- }
- }
+ tasks.push(params);
+ }
- }, sec * 1000);
- }
-
-
- function reportOfflineNodeStatus(line) {
-
- logger.info("Cmd-mngr: ------>reportOffLineNodeStatus for line ", line);
-
- values = {};
- values["dimming"] = 0;//brightness
- values["power"] = 0;//výkon
- values["current"] = 0;//prúd
- values["status"] = "OFFLINE";
-
- const date = Date.now();
-
- Object.keys(nodesData).forEach(node => {
-
- //potrebujem nody k danej linii
- if (line == nodesData[node].line || line == undefined) {
-
- let tbname = nodesData[node].tbname;
- let nodeStatus = nodesData[node].status;
-
- //in case we have reported offline node status, we return (continue with next node)
- if (nodeStatus === "OFFLINE") return;
-
- nodesData[node].node_status_before_offline = nodeStatus;
- nodesData[node].status = "OFFLINE";
- nodesData[node].readout = {};
-
- sendTelemetry({ ...values }, tbname, date);
- }
- });
-
- }
-
-
- function turnLine(onOrOff, line, info) {
- let obj = {
- line: line,
- command: onOrOff,
- info: info
- };
-
- //logger.debug("linia", line, obj);
- instance.send(SEND_TO.dido_controller, obj);
- }
-
-
- function detectIfResponseIsValid(bytes) {
- //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
- let type = "RESPONSE";
- if (bytes.length == 1) type = "BROADCAST"; // odpoved z rsPortu na broadcast command: ["broadcast"]
- else if (bytes[4] == 0) type = "RESPONSE";
- else if (bytes[4] == 1) type = "ERROR";
- else if (bytes[4] == 2) type = "EVENT";
- else type = "UNKNOWN";
+ }
+ }
- let message = "OK";
- let error = "";
- if (type == "BROADCAST") return { message, type, error };
+ }, sec * 1000);
+ }
- let crc = crc16('ARC', bytes.slice(0, 9));
- let c1 = (crc >> 8) & 0xFF;
- let c2 = crc & 0xFF;
- if (c1 != bytes[9]) {
- //CRC_ERROR
- message = "NOK";
- error = "CRC_ERROR c1";
- instance.send(SEND_TO.debug, "CRC_ERROR c1");
- }
+ function reportOfflineNodeStatus(line) {
+
+ logger.debug("Cmd-mngr: ------>reportOfflineNodeStatus for line", line);
+
+ values = {};
+ values["dimming"] = 0;//brightness
+ values["power"] = 0;//výkon
+ values["current"] = 0;//prúd
+ values["status"] = "OFFLINE";
+
+ const date = Date.now();
- if (c2 != bytes[10]) {
- //CRC_ERROR
- message = "NOK";
- error = "CRC_ERROR c2";
- instance.send(SEND_TO.debug, "CRC_ERROR c2");
- }
+ Object.keys(nodesData).forEach(node => {
- //crc error
- if (type != "RESPONSE") {
- instance.send(SEND_TO.debug, bytes);
- instance.send(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4]);
+ //potrebujem nody k danej linii
+ if (line == nodesData[node].line || line == undefined) {
+
+ let tbname = nodesData[node].tbname;
+ let nodeStatus = nodesData[node].status;
+
+ //in case we have reported offline node status, we return (continue with next node)
+ if (nodeStatus === "OFFLINE") return;
+
+ nodesData[node].node_status_before_offline = nodeStatus;
+ nodesData[node].status = "OFFLINE";
+ nodesData[node].readout = {};
+
+ sendTelemetry({ ...values }, tbname, date);
+ }
+ })
- //logger.debug(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4], bytes);
+ }
- error = "type is: " + type;
- message = "NOK";
- }
+ function turnLine(onOrOff, line, info) {
+ let obj = {
+ line: line,
+ command: onOrOff,
+ info: info
+ };
+
+ //logger.debug("linia", line, obj);
+ instance.send(SEND_TO.dido_controller, obj);
+ }
- return { message, type, error };
- }
- //BUILD TASKS//
- function buildTasks(params) {
+ function detectIfResponseIsValid(bytes) {
+ //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
+ let type = "RESPONSE";
+ if (bytes.length == 1) type = "BROADCAST"; // odpoved z rsPortu na broadcast command: ["broadcast"]
+ else if (bytes[4] == 0) type = "RESPONSE";
+ else if (bytes[4] == 1) type = "ERROR";
+ else if (bytes[4] == 2) type = "EVENT";
+ else type = "UNKNOWN";
- //return;
- console.log("buidTAaasks start ****************", params);
- monitor.info("buildTasks - params", params);
+ let message = "OK";
+ let error = "";
+ if (type == "BROADCAST") return { message, type, error };
- let processLine; //defined line
- let init = false;
- let processLineProfiles = true;
- let processBroadcast = true;
- let processNodes = true;
+ let crc = crc16('ARC', bytes.slice(0, 9));
+ let c1 = (crc >> 8) & 0xFF;
+ let c2 = crc & 0xFF;
- if (params == undefined) {
- init = true;
- tasks = [];
- logger.debug("-->buildTasks clear tasks");
- }
- else {
- processLineProfiles = false;
- processBroadcast = false;
- processNodes = false;
+ if (c1 != bytes[9]) {
+ //CRC_ERROR
+ message = "NOK";
+ error = "CRC_ERROR c1";
+ instance.send(SEND_TO.debug, "CRC_ERROR c1");
+ }
- processLineProfiles = params.processLineProfiles;
- processLine = params.line;
- }
+ if (c2 != bytes[10]) {
+ //CRC_ERROR
+ message = "NOK";
+ error = "CRC_ERROR c2";
+ instance.send(SEND_TO.debug, "CRC_ERROR c2");
+ }
- let now = new Date();
+ //crc error
+ if (type != "RESPONSE") {
+ instance.send(SEND_TO.debug, bytes);
+ instance.send(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4]);
- //process line profiles
- if (processLineProfiles) {
+ //logger.debug(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4], bytes);
- let keys = Object.keys(relaysData);
+ error = "type is: " + type;
- for (let i = 0; i < keys.length; i++) {
+ message = "NOK";
+ }
- let line = parseInt(keys[i]);
- let profilestr = relaysData[line].profile;
+ return { message, type, error };
+ }
- if (processLine != undefined) {
- if (processLine != line) continue;
- }
- try {
+ //BUILD TASKS//
+ function buildTasks(params) {
- /**
- * we process line profiles: timepoints, astro clock, lux_sensor, offsets ...
- */
- if (profilestr === "") throw ("Profile is not defined");
- let profile = JSON.parse(profilestr);
- if (Object.keys(profile).length === 0) throw ("Profile is empty");
+ //return;
+ console.log("buidTAaasks start ****************", params);
+ monitor.info("buildTasks - params", params);
- monitor.info("buildTasks: profile for line", line);
- monitor.info("profile:", profile);
+ let processLine; //defined line
+ let init = false;
+ let processLineProfiles = true;
+ let processBroadcast = true;
+ let processNodes = true;
- let time_points = profile.intervals;
+ if (params == undefined) {
+ init = true;
+ tasks = [];
+ logger.debug("-->buildTasks clear tasks");
+ }
+ else {
+ processLineProfiles = false;
+ processBroadcast = false;
+ processNodes = false;
- // add name to regular profile timepoint and delete unused end_time key:
- time_points.forEach(point => {
- point.name = "profileTimepoint"
- delete point.end_time;
- });
+ processLineProfiles = params.processLineProfiles;
+ processLine = params.line;
+ }
- //monitor.info("buildTasks: time_points", time_points);
+ let now = new Date();
+ //process line profiles
+ if (processLineProfiles) {
- /**
- * if astro_clock is true, we create timepoints, that switch on/off relays accordingly.
- * we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn
- * if dawn/dusk_lux_sensor is true, it has higher priority than astro_clock switching
- */
- if (profile.astro_clock == true) {
+ let keys = Object.keys(relaysData);
- // if astro clock true, we remove all regular profile points
- time_points = [];
+ for (let i = 0; i < keys.length; i++) {
- let sunCalcResult = calculateDuskDawn(new Date(), line);
+ let line = parseInt(keys[i]);
+ let profilestr = relaysData[line].profile;
- // adding dusk dawn to timpoints
- if (profile.dawn_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dawn"], "value": 0, "name": "dawn" });
- if (profile.dusk_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dusk"], "value": 1, "name": "dusk" });
+ if (processLine != undefined) {
+ if (processLine != line) continue;
+ }
- //if dusk/dawn is true, lines will switch on/off according to lux_sensor value. In case it fails, we create lux_timepoints, to make sure lines will switch on/off (aby nam to nezostalo svietit)
- //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
- if (profile.dawn_lux_sensor == true) {
- let [ahours, aminutes] = sunCalcResult["dawn"].split(':');
- let ad = new Date();
- ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dawn_lux_sensor_time_window, 0);
+ try {
- let strDate = ad.getHours() + ":" + ad.getMinutes();
- time_points.push({ "value": 0, "start_time": strDate, "name": "luxOff" });
- }
+ /**
+ * we process line profiles: timepoints, astro clock, lux_sensor, offsets ...
+ */
+ if (profilestr === "") throw ("Profile is not defined");
+ let profile = JSON.parse(profilestr);
+ if (Object.keys(profile).length === 0) throw ("Profile is empty");
- if (profile.dusk_lux_sensor == true) {
- let [ahours, aminutes] = sunCalcResult["dusk"].split(':');
- let ad = new Date();
- ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dusk_lux_sensor_time_window, 0);
+ monitor.info("buildTasks: profile for line", line);
+ monitor.info("profile:", profile);
- let strDate = ad.getHours() + ":" + ad.getMinutes();
- time_points.push({ "value": 1, "start_time": strDate, "name": "luxOn" });
- //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing
- }
- }
+ let time_points = profile.intervals;
- //sort time_points
- time_points.sort(function(a, b) {
+ // add name to regular profile timepoint and delete unused end_time key:
+ time_points.forEach(point => {
+ point.name = "profileTimepoint"
+ delete point.end_time;
+ });
- let [ahours, aminutes] = a.start_time.split(':');
- let [bhours, bminutes] = b.start_time.split(':');
+ //monitor.info("buildTasks: time_points", time_points);
- let ad = new Date();
- ad.setHours(parseInt(ahours), parseInt(aminutes), 0);
- let bd = new Date();
- bd.setHours(parseInt(bhours), parseInt(bminutes), 0);
+ /**
+ * if astro_clock is true, we create timepoints, that switch on/off relays accordingly.
+ * we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn
+ * if dawn/dusk_lux_sensor is true, it has higher priority than astro_clock switching
+ */
+ if (profile.astro_clock == true) {
- return ad.getTime() - bd.getTime();
- });
+ // if astro clock true, we remove all regular profile points
+ time_points = [];
- console.log("line timepoints ........", time_points);
+ let sunCalcResult = calculateDuskDawn(new Date(), line);
- let currentValue = 0;
- if (time_points.length > 0) currentValue = time_points[time_points.length - 1].value;
+ // adding dusk dawn to timpoints
+ if (profile.dawn_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dawn"], "value": 0, "name": "dawn" });
+ if (profile.dusk_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dusk"], "value": 1, "name": "dusk" });
- monitor.info("-->comming events turn on/off lines:");
- for (let t = 0; t < time_points.length; t++) {
+ //if dusk/dawn is true, lines will switch on/off according to lux_sensor value. In case it fails, we create lux_timepoints, to make sure lines will switch on/off (aby nam to nezostalo svietit)
+ //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
+ if (profile.dawn_lux_sensor == true) {
+ let [ahours, aminutes] = sunCalcResult["dawn"].split(':');
+ let ad = new Date();
+ ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dawn_lux_sensor_time_window, 0);
- let start_time = new Date();
- let [hours, minutes] = time_points[t].start_time.split(':');
- start_time.setHours(parseInt(hours), parseInt(minutes), 0);
+ let strDate = ad.getHours() + ":" + ad.getMinutes();
+ time_points.push({ "value": 0, "start_time": strDate, "name": "luxOff" });
+ }
- //task is in the past
- if (now.getTime() > start_time.getTime()) {
- currentValue = time_points[t].value;
+ if (profile.dusk_lux_sensor == true) {
+ let [ahours, aminutes] = sunCalcResult["dusk"].split(':');
+ let ad = new Date();
+ ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dusk_lux_sensor_time_window, 0);
- //timepoint is in past, we add 24 hours
- start_time.setDate(start_time.getDate() + 1);
- }
-
- let params = getParams();
- params.type = "relay";
- params.line = parseInt(line);
- params.value = time_points[t].value;
- params.tbname = relaysData[line].tbname;
- params.timestamp = start_time.getTime();
-
- // it timepoints are not calculated (dawn, dusk, lux_timepoint), but static points in line profile, we just repeat the task every day
- if (time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24 * 60;
-
- //astro timepoints will be recalculated dynamically:
- params.timePointName = time_points[t].name;
-
- // if astro timepoint, we save time window:
- if (['luxOn', 'luxOff', 'dusk', 'dawn'].includes(params.timePointName)) {
- params.dawn_lux_sensor_time_window = profile.dawn_lux_sensor_time_window;
- params.dusk_lux_sensor_time_window = profile.dusk_lux_sensor_time_window;
- }
-
- if (params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line;
- else if (params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line;
-
- params.debug = true;
-
- //turn on/off line
- tasks.push(params);
- monitor.info("TimePoint params: ", params.info, start_time);
- }
-
- monitor.info("-->time_points final", line, time_points);
-
- //ensure to turn on/off according to calculated currentValue
- let params = getParams();
- params.type = "relay";
- params.line = parseInt(line);
- params.tbname = relaysData[line].tbname;
- params.value = currentValue;
- params.timestamp = i;
- params.debug = true;
-
- //logger.debug(now.toLocaleString("sk-SK"));
- monitor.info("-->currentValue for relay", line, currentValue);
-
- //turn on/off line
- if (params.value == 0) params.info = "turn off line on startup: " + line;
- else if (params.value == 1) params.info = "turn on line on startup: " + line;
-
- tasks.push(params);
-
- } catch (error) {
- if (profilestr !== "") {
- //errLogger.error(profilestr, error);
- console.log(`Cmd_mngr: Unable to process line profile ${line}. Error: `, error);
- errorHandler.sendMessageToService(profilestr + "-" + error, 0, "js_error");
- } else {
- turnLine("off", line, "No line profile. Switching it off on startup");
- }
- }
+ let strDate = ad.getHours() + ":" + ad.getMinutes();
+ time_points.push({ "value": 1, "start_time": strDate, "name": "luxOn" });
+ //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing
+ }
+ }
- }
- //logger.debug("tasks:");
- //logger.debug(tasks);
- }
+ //sort time_points
+ time_points.sort(function(a, b) {
+ let [ahours, aminutes] = a.start_time.split(':');
+ let [bhours, bminutes] = b.start_time.split(':');
- //NOTE: PROCESS DEFAULT BROADCASTS - Time of dusk, Time of dawn, Actual Time
- if (processBroadcast) {
+ let ad = new Date();
+ ad.setHours(parseInt(ahours), parseInt(aminutes), 0);
- let d = new Date();
- let time = d.getTime();
- let sunCalcResult = calculateDuskDawn();
-
- {
- let params = getParams();
-
- params.address = 0xffffffff;//broadcast
- params.byte1 = sunCalcResult["dusk_hours"];
- params.byte2 = sunCalcResult["dusk_minutes"];
- params.recipient = 2;//2 broadcast,
- params.register = 6;//Time of dusk
- params.rw = 1;//write
- params.type = "node-regular-write";
- params.timestamp = time + 60000;
- params.addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk
- params.info = "Broadcast-duskTime";
-
- tasks.push(params);
- }
-
- {
- let params = getParams();
-
- params.address = 0xffffffff;//broadcast
- params.byte1 = sunCalcResult["dawn_hours"];
- params.byte2 = sunCalcResult["dawn_minutes"];
- params.recipient = 2; //2 broadcast
- params.register = 7;//Time of dawn
- params.rw = 1;//write
- params.type = "node-regular-write";
- params.timestamp = time + 60001;
- params.addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn
- params.info = "Broadcast-dawnTime";
-
- tasks.push(params);
- }
-
- {
- let params = getParams();
-
- params.address = 0xffffffff;//broadcast
- params.byte1 = d.getHours();
- params.byte2 = d.getMinutes();
- params.recipient = 2; //2 broadcast
- params.register = 87;//Actual time
- params.rw = 1;//write
- params.type = "node-regular-write";
- params.timestamp = time + 60002;
- params.addMinutesToTimestamp = 5;
- params.info = "run broadcast: Actual time";
-
- tasks.push(params);
- }
-
- }
-
- //process nodes & tasks - read node's data
- if (processNodes) {
-
- let time = Date.now();
-
- for (let k in nodesData) {
- let address = parseInt(k);
- let tbname = nodesData[k].tbname;
- let register = 0;
-
- for (let i = 0; i < listOfCommands.length; i++) {
-
- register = listOfCommands[i];
- let addMinutesToTimestamp = priorities[register];
-
- let params = getParams();
-
- params.address = address;
- params.recipient = 1;
- params.register = register;
- params.type = register == 1 ? "node-dimming-read" : "node-regular-read";
- params.tbname = tbname;
- params.timestamp = time + 5000 + i * 500 + addMinutesToTimestamp * 1000; //to make slight time difference
- params.addMinutesToTimestamp = addMinutesToTimestamp;
- params.info = "Node regular read command";
-
- tasks.push(params);
- }
-
- }
- }
-
-
- //niektore ulohy sa vygeneruju iba 1x pri starte!!!
- if (!init) return;
-
-
- //Master node FW version - modifies SETTINGS.masterNodeIsResponding
- {
- let params = getParams();
- params.type = "cmd-master";
- params.register = 4;
- params.address = 0;
- params.timestamp = 0;
- params.addMinutesToTimestamp = 5;
- params.tbname = SETTINGS.rvoTbName;
- params.info = "Master node FW verzia";
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //kazdu hodinu skontrolovat nastavenie profilov
- {
- let params = getParams();
- params.type = "process_profiles";
- params.timestamp = Date.now() + 60001;
- params.addMinutesToTimestamp = 60;//60 = every hour
- params.info = "detekcia nespracovaných profilov linie a nodov";
- //params.debug = true;
-
- tasks.push(params);
- }
-
- monitor.info("tasks created:", tasks.length);
- }
-
-
- /**
- * We process line profile, where "astro_clock": true
- * example profile:
- *
- "dawn_lux_sensor": true,
- "dusk_lux_sensor": true,
- "dawn_lux_sensor_value": 5,
- "dusk_lux_sensor_value": 5,
- "dawn_astro_clock_offset": 0,
- "dusk_astro_clock_offset": 10,
- "dawn_lux_sensor_time_window": 30,
- "dusk_lux_sensor_time_window": 30,
- "dawn_astro_clock_time_window": 60,
- "dusk_astro_clock_time_window": 60
-
- * if dawn: if currentTimestamp is in timewindow "dawnTime + and - dawn_lux_sensor_time_window" and lux value >= lux_sensor_value, we switch off the line.
- * if dusk: we do oposite
- *
- * dawn: usvit - lux je nad hranicou - vypnem
- * dusk: sumrak - lux je pod hranicou - zapnem
- */
- function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) {
-
- let now = new Date();
- let currentTimestamp = now.getTime();
- let keys = Object.keys(relaysData);
-
- for (let i = 0; i < keys.length; i++) {
-
- let line = keys[i]; //line is turned off by default
- let profilestr = relaysData[line].profile;
- const contactor = relaysData[line].contactor;
-
- try {
-
- let profile = JSON.parse(profilestr);
- if (Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined");
-
- if (profile.astro_clock == true) {
- let sunCalcResult = calculateDuskDawn(now, line);
-
- //usvit
- if (profile.dawn_lux_sensor == true) {
- let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
- let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60);
-
- if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
- if (lux_sensor_value > profile.dawn_lux_sensor_value) {
- if (contactor) turnLine("off", line, "Profile: dawn - turnOff line according to lux sensor");
- }
- }
- }
-
- //sumrak
- if (profile.dusk_lux_sensor == true) {
- let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
- let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
-
- if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
- if (lux_sensor_value < profile.dusk_lux_sensor_value) {
- if (!contactor) turnLine("on", line, "Profile: dusk - turnOn line according to lux sensor");
- }
- }
- }
-
- }
-
- } catch (error) {
- if (profilestr !== "") monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error);
- }
-
- }
-
- }
-
- /**
- * function updates status and time_of_last_communication of node in the dbNodes
- * it only updates if conditions are met
- * it only updates time_of_last_communication of node, if the last written time was more than 10 minutes ago (600000 miliseconds)
- * if newStatus of node is always receiving false, and it is already for more than SETTINGS.node_status_nok_time value, we update status to "NOK" in tb
- * function returns true, if status of node needs to be updated in TB (newStatus attribute is false in this case).
- */
- function updateNodeStatus(node, newStatus) {
- //MASTER
- if (node == 0) return;
-
- let nodeObj = nodesData[node];
- if (nodeObj == undefined) return;
-
- let nodeCurrentStatus = nodeObj.status;
- const now = Date.now();
-
- let data = null;
-
- if (nodeCurrentStatus === "OFFLINE") {
- data = { status: newStatus };
- nodeDbStatusModify(node, data);
- return;
- }
- else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication > now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) return;
- else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication < now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) {
- data = { time_of_last_communication: now };
- nodeDbStatusModify(node, data);
- return;
- }
- else if (newStatus == false && nodeCurrentStatus == false) return true;
- else if (newStatus == false && nodeCurrentStatus == true) {
- if (nodeObj.time_of_last_communication + SETTINGS.node_status_nok_time > now) return;
- else {
- data = { status: newStatus };
- nodeDbStatusModify(node, data);
- return true;
- }
- }
- else if (newStatus == true && nodeCurrentStatus == false) {
- data = { status: newStatus, time_of_last_communication: now };
- nodeDbStatusModify(node, data);
- return;
- }
-
- }
-
-
- function nodeDbStatusModify(node, data) {
- dbNodes.modify(data).where("node", node).make(function(builder) {
- builder.callback(function(err, response) {
- if (!err) {
- nodesData[node] = { ...nodesData[node], ...data };
- }
- });
- });
- }
-
-
- async function runTasks() {
-
- clearInterval(interval);
-
- let currentTimestamp = Date.now();
-
- //report dusk, dawn---------------------------------
- if (reportDuskDawn.dusk_time < currentTimestamp) {
- //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
- if ((currentTimestamp - reportDuskDawn.dusk_time) < 60 * 1000) {
- //reportovali sme?
- if (reportDuskDawn.dusk_time_reported != sunCalcResult.dusk_time) {
- //sendNotification("Cmd-mngr: calculated Time of dusk", SETTINGS.rvoTbName, "dusk_has_occured", { value: sunCalcResult["dusk"] }, "", SEND_TO.tb, instance);
- reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time;
- }
- }
-
- var nextDay = new Date();
- nextDay.setDate(nextDay.getDate() + 1);
-
- sunCalcResult = calculateDuskDawn(nextDay);
- reportDuskDawn.dusk_time = sunCalcResult.dusk_time;
- }
-
- if (reportDuskDawn.dawn_time < currentTimestamp) {
- //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
- if ((currentTimestamp - reportDuskDawn.dawn_time) < 60 * 1000) {
- //reportovali sme?
- if (reportDuskDawn.dawn_time_reported != sunCalcResult.dawn_time) {
- //sendNotification(": calculated Time of dawn", SETTINGS.rvoTbName, "dawn_has_occured", { value: sunCalcResult["dawn"] }, "", SEND_TO.tb, instance);
- reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time;
- }
- }
-
- var nextDay = new Date();
- nextDay.setDate(nextDay.getDate() + 1);
-
- sunCalcResult = calculateDuskDawn(nextDay);
- reportDuskDawn.dawn_time = sunCalcResult.dawn_time;
-
- }
- //--------------------------------------------------------
-
- //sort tasks based on timestamp
- tasks.sort(function(a, b) {
- if (a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp) {
- return a.priority - b.priority;
- }
- return a.timestamp - b.timestamp;
- });
-
- if (tasks.length == 0) {
- instance.send(SEND_TO.debug, "no tasks created");
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- if (!rsPort.isOpen) {
- instance.send(SEND_TO.debug, "!rsPort.isOpen");
- //await rsPort.open();
- //console.log("Cmd-mngr: !rsPort.isOpen");
- }
-
- let currentTask = tasks[0];
-
- if (currentTask.debug) {
- //logger.debug("--->task to process", currentTask);
- }
-
- if (currentTask.timestamp <= currentTimestamp) {
- let params = { ...tasks[0] };
-
- //allow terminal commands
- if (SETTINGS.maintenance_mode && params.type !== "cmd-terminal") {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- let type = params.type;
- let tbname = params.tbname;
- let node = params.address;
- let register = params.register;
- let line = null;
- let itIsNodeCommand;
-
- if (nodesData[node] !== undefined) {
- line = nodesData[node].line;
- itIsNodeCommand = true;
- }
-
- if (params.line !== undefined) line = params.line;
-
- if (params.addMinutesToTimestamp > 0 || params.timePointName) {
- tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
- } else {
- tasks.shift();
- }
-
- //kontrola nespracovanych profilov nodov
- if (type == "process_profiles") {
- //na vsetky zapnutych liniach sa spracuju nespracovane profily nodov
- loadRelaysData();
- interval = setInterval(runTasks, SHORT_INTERVAL);
- return;
- }
-
- //relay
- if (type == "relay") {
-
- const timePointName = params.timePointName;
- const value = params.value;
-
- let date = new Date();
- date.setDate(date.getDate() + 1);//next day
-
- let sunCalcResult;
- if (timePointName) sunCalcResult = calculateDuskDawn(date, params.line);
-
- if (timePointName == "dawn") {
- tasks[0].timestamp = sunCalcResult.dawn_time;
- }
- else if (timePointName == "dusk") {
- tasks[0].timestamp = sunCalcResult.dusk_time;
- }
- else if (timePointName == "luxOn") {
- tasks[0].timestamp = sunCalcResult.dusk_time + params.dusk_lux_sensor_time_window * 60000;
- }
- else if (timePointName == "luxOff") {
- tasks[0].timestamp = sunCalcResult.dawn_time + params.dawn_lux_sensor_time_window * 60000;
- }
- else if (timePointName == "profileTimepoint") {
- tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
- }
-
- let info = "aplikovany bod profilu";
- let onOrOff = "";
- value == 1 ? onOrOff = "on" : onOrOff = "off";
-
- turnLine(onOrOff, params.line, info);
-
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- if (!SETTINGS.masterNodeIsResponding) {
- //ak neodpoveda, nebudeme vykonavat ziadne commands, okrem cmd-terminal cmd-master
- errorHandler.sendMessageToService("Master node is not responding");
-
- let stop = true;
-
- if (type === "cmd-terminal" || type === "cmd-master") stop = false;
- if (stop) {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
- }
-
- let contactorStatus = 1;
- if (relaysData[line] != undefined) contactorStatus = relaysData[line].contactor;
-
- if (line === 0 || contactorStatus === 0 || FLOW.deviceStatus.state_of_breaker[line] === "Off") {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- // TODO: -> status offline for rvo if rotary_switch_state is OFF, this is source of errors
- // check if rotary_switch_state == "Off"
- // state_of_braker: disconnected = true?
-
- if (!rsPort.isOpen) {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- //RE-CALCULATE VALUES
- //set actual time for broadcast
- if (register == 87 && params.recipient === 2) {
- var d = new Date();
- params.byte1 = d.getHours();//h
- params.byte2 = d.getMinutes();//m
- }
-
- //SET DUSK/DAWN FOR BROADCAST
- //Time of dusk
- if (register == 6 && params.recipient === 2) {
-
- if (type != "cmd-terminal") {
- let sunCalcResult = calculateDuskDawn();
- params.byte1 = sunCalcResult["dusk_hours"];//h
- params.byte2 = sunCalcResult["dusk_minutes"];//m
- }
- }
-
- //Time of dawn
- if (register == 7 && params.recipient === 2) {
- if (type != "cmd-terminal") {
- let sunCalcResult = calculateDuskDawn();
- params.byte1 = sunCalcResult["dawn_hours"];//h
- params.byte2 = sunCalcResult["dawn_minutes"];//m
- }
- }
- //-----------------------
-
- instance.send(SEND_TO.debug, "address: " + node + " register:" + register + "type: " + type);
-
- var startTime, endTime;
- startTime = new Date();
-
- let saveToTb = true;
- if (!tbname) saveToTb = false;
-
- let resp = com_generic(node, params.recipient, params.rw, register, params.name, params.byte1, params.byte2, params.byte3, params.byte4);
- let readBytes = 11;
- let timeout = 4000;
-
-
- // await keyword is important, otherwise incorrect data is returned!
- await writeData(rsPort, resp, readBytes, timeout).then(function(data) {
-
- //sometimes happens, that status of node changes even if line was turned off and should be offline. To prevent this, we return if line contactor is 0:
- if (itIsNodeCommand && line && relaysData[line].contactor !== 1) return;
-
- endTime = new Date();
- var timeDiff = endTime - startTime;
-
- //data je array z 11 bytov: 1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data a 2 byty CRC
- let dataBytes = data.slice(5, 9);
- let result = detectIfResponseIsValid(data);
-
- //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
- let message = result.message; // OK, NOK
- let message_type = result.type;
-
- if (params.hasOwnProperty("debug")) {
- if (params.debug) {
- console.log("detected response:", result);
- logger.debug("Cmd-mngr: writeData done " + message_type + " duration: " + timeDiff + " type: " + params.debug, params, result);
- }
- }
-
- let values = {};
-
- //CMD FINISHED
- if (message == "OK") {
-
- updateNodeStatus(node, true);
-
- //write
- if (type == "set_node_profile") {
- let result = cmdCounterResolve(node);
- if (result == 0) {
- dbNodes.modify({ processed: true }).where("node", node).make(function(builder) {
- builder.callback(function(err, response) {
-
- sendNotification("Cmd-mngr: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: node }, "", SEND_TO.tb, instance);
-
- logger.debug("--> profil úspešne odoslaný na node č. " + node);
- nodesData[node].processed = true;
- nodeProfileSendFail.delete(node);
- });
- });
- }
- }
-
- //parse read response
- if (params.rw == 0) {
- values = processResponse(register, dataBytes); //read
- }
-
- if (itIsNodeCommand) {
- values.comm_status = "OK";
- values.status = "OK";
- nodesData[node].readout = { ...nodesData[node].readout, ...values };
- }
-
- //master node
- if (node == 0) {
- sendNotification("Cmd-mngr: process cmd", SETTINGS.rvoTbName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status");
- SETTINGS.masterNodeIsResponding = true;
- if (register == 4) values["edge_fw_version"] = SETTINGS.edge_fw_version;
- }
-
- if (params.debug) {
- //logger.debug("saveToTb", saveToTb, tbname, values);
- }
-
- if (saveToTb && type != "node-regular-read") {
- sendTelemetry(values, tbname);
- }
- else {
- if (type == "cmd-terminal") {
- terminalCommandResponse(params, "SUCCESS", data);
- }
- }
-
- }
- else {
- terminalCommandResponse(params, "ERROR", data);
- handleNokResponseOnRsPort("handleNOK else block", params, itIsNodeCommand, saveToTb);
-
- if (params.hasOwnProperty("debug")) {
- if (params.debug) {
- //logger.debug("writeData err: ", error, result, params);
- logger.debug("writeData err: ", tbname, node, register, values);
- }
- }
-
- //logger.debug(error, result, params);
- }
- }).catch(function(reason) {
-
- //console.log("writeData catch exception", reason);
- instance.send(SEND_TO.debug, reason);
-
- terminalCommandResponse(params, "FAILURE", null, reason);
- handleNokResponseOnRsPort("handleNOK catch block", params, itIsNodeCommand, saveToTb);
-
- if (params.hasOwnProperty("debug")) {
- if (params.debug) {
- logger.debug("-->WRITE FAILED: " + reason, params.debug, params);
- }
- }
-
- });
-
- }
- else {
- if (currentTask.debug) {
- // currentTask.timestamp <= currentTimestamp && logger.debug("currentTask is not processed - task is in the future", currentTask);
- }
-
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- //console.log("----->runTasks - setInterval", new Date());
- interval = setInterval(runTasks, SHORT_INTERVAL);
- }
-
-
- function repeatCommand(params) {
- params.repeatCounter++;
- if (params.repeatCounter < 4) {
- params.timestamp = 0;
- params.addMinutesToTimestamp = 0;
- tasks.push(params);
- }
- }
-
- function handleNokResponseOnRsPort(message, params, itIsNodeCommand, saveToTb) {
-
- let node = params.address;
- let register = params.register;
- let type = params.type;
- let tbName = params.tbname;
- if (!tbName) return;
-
- let values = {};
-
- let updateStatus = updateNodeStatus(node, false);
-
- if (itIsNodeCommand) {
- values.comm_status = "NOK";
- nodesData[node].readout.comm_status = "NOK";
- repeatCommand(params);
- }
-
- if (updateStatus) {
- values.status = "NOK";
- nodesData[node].readout.status = "NOK";
- }
-
- if (type === "node-regular-read") return;
-
- //master node
- if (node == 0) {
- sendNotification("Cmd-mngr: process cmd", SETTINGS.rvoTbName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
- logger.debug("master_node_is_not_responding", params);
- SETTINGS.masterNodeIsResponding = false;
-
- if (register == 4) values["master_node_version"] = "NOK";
- }
-
- if (type == "set_node_profile") {
- delete cmdCounter[node];
- logger.debug("profil nebol úspešne odoslaný na node č. ", params);
-
- if (!nodeProfileSendFail.has(node)) {
- sendNotification("Cmd-mngr: process cmd", tbName, "configuration_of_dimming_profile_to_node_failed", { node: node }, "", SEND_TO.tb, instance);
- nodeProfileSendFail.add(node);
- }
- }
-
- // console.log("------",node, register, type, itIsNodeCommand, updateStatus, saveToTb, values);
- if (saveToTb) {
- sendTelemetry(values, tbName);
- }
-
- }
-
-
- function sendNodesData() {
- Object.keys(nodesData).forEach(node => {
- if (nodesData[node]["status"] !== "OFFLINE") {
- sendTelemetry(nodesData[node].readout, nodesData[node].tbname);
- nodesData[node].readout = {};
- }
- })
- }
-
-
- /**
- * function handles requests from terminal
- * responseType can be "SUCCESS", "ERROR" or "FAILURE", depending on rsPort data.
- * FAILURE means, that we got into catch block of writeData function.
- */
- function terminalCommandResponse(params, responseType, data = null, reason = "") { //success, error, failure
-
- if (params.refFlowdataKey === undefined) {
- //console.log("params.refFlowdataKey is undefined", params);
- return;
- }
-
- let message = null;
- let type = null;
-
- switch (responseType) {
- case "SUCCESS":
- message = "cmd-terminal SUCCESS";
- type = "SUCCESS";
- break;
- case "ERROR":
- message = "cmd-terminal FAILED";
- type = "ERROR";
- break;
- case "FAILURE":
- message = "ERROR WRITE FAILED: " + reason;
- type = "ERROR";
- break;
- default:
- type = undefined;
- }
-
- logger.debug(message);
-
- //make http response
- let responseObj = {}
- responseObj["type"] = type;
-
- if (responseType == "FAILURE") responseObj["message"] = "ERROR WRITE FAILED: " + reason;
- else responseObj["bytes"] = data;
-
- let refFlowdata = refFlowdataObj[params.refFlowdataKey]; //holds reference to httprequest flowdata
- if (refFlowdata) {
- refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, refFlowdata);
- }
- }
-
-
- /**
- * function handles tasks, that are not needed to run through masterNode. To make them run smooth without waiting for other tasks to be completed, we moved them in separate function
- */
- function reportEdgeDateTimeAndNumberOfLuminaires() {
-
- //Number of ok and nok nodes on platform does not equals to total number of nodes.
- //possible error is, that nodesData object is changing all the time. To make a proper calculation of ok,nok luminaires, we make a copy of it:
- let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
-
- const ts = Date.now();
- const keys = Object.keys(nodesData_clone);
-
- const number_of_luminaires = keys.length;
- let number_of_ok_luminaires = 0;
- let number_of_nok_luminaires = 0;
-
- for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
- let nodeObj = nodesData_clone[key];
- if (nodeObj.tbname == undefined) continue;
-
- if (nodeObj.status === "OFFLINE") {
- nodeObj.node_status_before_offline === true ? number_of_ok_luminaires++ : number_of_nok_luminaires++;
- }
- else if (nodeObj.status == true) number_of_ok_luminaires++;
- else number_of_nok_luminaires++;
-
- }
-
- const values = {
- "number_of_luminaires": number_of_luminaires,
- "number_of_ok_luminaires": number_of_ok_luminaires,
- "number_of_nok_luminaires": number_of_nok_luminaires,
- "edge_date_time": ts - ts % 60000 //round to full minute
- };
-
- sendTelemetry(values, SETTINGS.rvoTbName, ts);
- }
-
-
- function handleRsPort() {
-
- if (rsPort) {
- rsPort.removeAllListeners();
- rsPort = null;
- }
-
- //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
- // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
- // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
-
- if (SETTINGS.serial_port == "" || SETTINGS.serial_port == undefined || SETTINGS.serial_port.length === 1) SETTINGS.serial_port = "ttymxc4";
- rsPort = new SerialPort(`/dev/${SETTINGS.serial_port}`, { autoOpen: false });
- //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
- //rsPort.setMaxListeners(0);
-
- rsPort.on('open', async function() {
-
- logger.debug("Cmd-mngr: rsPort opened success");
-
- await runSyncExec(`stty -F /dev/${SETTINGS.serial_port} 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke`).then(function(status) {
- instance.send(SEND_TO.debug, "RPC runSyncExec - Promise Resolved:" + status);
-
- logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status);
-
- }).catch(function(reason) {
- instance.send(SEND_TO.debug, "Cmd-mngr: RPC runSyncExec - promise rejected:" + reason);
- });
- });
-
- rsPort.on('error', function(err) {
- errorHandler.sendMessageToService([exports.title, "unable to open port", SETTINGS.serial_port, err.message], 0);
- monitor.info("Cmd-mngr: Error on rsPort", err.message);
- });
-
- rsPort.on("close", () => {
- monitor.info("Cmd-mngr: rsPort closed, reconnecting...");
- setTimeout(handleRsPort, 1000);
- });
-
- rsPort.open();
- }
-
-
- instance.on("close", () => {
- clearInterval(interval);
- clearInterval(customTasksInterval);
- clearInterval(setCorrectTime);
- clearInterval(sendNodeReadout);
- clearInterval(accelerometerInterval);
- rsPort.close();
- });
-
- instance.on("0", _ => {
- main();
- })
-
- instance.on("1", async function(flowdata) {
-
- //instance.send(SEND_TO.debug, "on Data");
- //instance.send(SEND_TO.debug, flowdata);
-
- //logger.debug(flowdata.data);
-
- //just testing functions
- if (flowdata.data == "open") {
- if (!rsPort.isOpen) rsPort.open();
- return;
- }
- else if (flowdata.data == "close") {
- rsPort.close();
- return;
- }
- else if (flowdata.data == "clean") {
- tasks = [];
- return;
- }
- else if (flowdata.data == "buildtasks") {
- //build & run
- return;
- }
- else if (flowdata.data == "run") {
- //durations = [];
-
- if (tasks.length == 0) {
-
- buildTasks();
-
- if (rsPort.isOpen) {
- interval = setInterval(runTasks, 100);
- }
- else {
- instance.send(SEND_TO.debug, "port is not opened!!!");
- }
- }
- }
- else {
- //terminal data - object
- //logger.debug("flowdata", flowdata.data);
-
- if (typeof flowdata.data === 'object') {
- //logger.debug("dido", flowdata.data);
- if (flowdata.data.hasOwnProperty("sender")) {
- //data from dido_controller
- if (flowdata.data.sender == "dido_controller") {
-
- if (flowdata.data.hasOwnProperty("cmd")) {
- let cmd = flowdata.data.cmd;
-
- if (cmd == "buildTasks") {
- clearInterval(interval);
-
- logger.debug("-->Cmd-mngr: BUILD TASKS");
- buildTasks();
-
- //logger.debug("tasks:");
- //logger.debug(tasks);
-
- logger.debug("-->Cmd-mngr: RUN TASKS");
- interval = setInterval(runTasks, 5000);
- }
- else if (cmd == "reload_relays") {
- loadRelaysData(flowdata.data.line);
-
- if (flowdata.data.dataChanged) {
- if (!flowdata.data.value) {
- reportOfflineNodeStatus(flowdata.data.line);
- }
- else {
- reportOnlineNodeStatus(flowdata.data.line);
- }
- }
-
- }
- else if (cmd == "rotary_switch_state") {
- let value = flowdata.data.value;
-
- //state was changed
- if (rotary_switch_state != value) {
- if (value == "Off") {
- //vyreportovat vsetky svietdla
- reportOfflineNodeStatus();
- }
-
- rotary_switch_state = value;
- }
- }
- else if (cmd == "lux_sensor") {
- lux_sensor = parseInt(flowdata.data.value);
-
- // POSSIBLE SOURCE OF PROBLEMS, IF USER SETS LUX TRESHOLD LEVEL GREATER THAN 100 - WE SHOULD BE CHECKING "DUSK/DAWN_LUX_SENSOR_VALUE" IN PROFILE MAYBE ??
- if (lux_sensor < 100) {
-
- // we send lux_sensor value to all nodes:
- let params = getParams(PRIORITY_TYPES.node_broadcast);
-
- params.recipient = 2;//2 broadcast, address = 0
- params.address = 0xffffffff;//Broadcast
-
- let ba = longToByteArray(lux_sensor);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- params.timestamp = PRIORITY_TYPES.node_broadcast;
- params.info = "run broadcast: Actual Lux level from cabinet";
- params.register = 95;//Actual Lux level from cabinet
- params.rw = 1;//write
-
- tasks.push(params);
-
- //process profiles
- turnOnOffLinesAccordingToLuxSensor(lux_sensor);
- }
- }
- else if (cmd == "state_of_breaker") {
- //istic linie
- let value = flowdata.data.value;
- let line = parseInt(flowdata.data.line);
-
- let dataChanged = false;
- if (state_of_breaker[line] != value) dataChanged = true;
-
- state_of_breaker[line] = value;
+ let bd = new Date();
+ bd.setHours(parseInt(bhours), parseInt(bminutes), 0);
- let status = "OK";
- if (value == "Off") status = "NOK";
-
- if (dataChanged) {
-
- if (relaysData.hasOwnProperty(line)) {
- let tbname = relaysData[line].tbname;
-
- if (value == "Off") sendNotification("Cmd-mngr: onData", tbname, "circuit_breaker_was_turned_off_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
- else sendNotification("Cmd-mngr: onData", tbname, "circuit_breaker_was_turned_on_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
-
- //report status liniu
- sendTelemetry({ status: status }, tbname)
-
- //current value
- if (value == "Off") reportOfflineNodeStatus(line); //vyreportovat vsetky svietidla na linii
- }
-
- }
- }
- else {
- logger.debug("undefined cmd", cmd);
- }
- }
- }
-
- return;
- }
-
- //data from worksys
- if (flowdata.data.hasOwnProperty("topic")) {
-
- let data = getNested(flowdata.data, "content", "data");
-
- //if we get temperature in senica from senica-prod01
- let temperature = getNested(flowdata.data, "content", "senica_temperature");
-
- if (temperature !== undefined) {
- temperatureInSenica = temperature;
- return;
- }
-
- if (data === undefined) {
- console.log("Invalid rpc command came from platform");
- return;
- }
-
- let command = data.params.command;
- let method = data.method;
- let profile = data.params.payload;
- if (profile == undefined) profile = "";
- let entity = data.params.entities[0];
- let entity_type = entity.entity_type;
- let tbname = entity.tb_name;
-
- instance.send(SEND_TO.debug, flowdata.data);
- logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method);
- logger.debug("----------------------------");
-
- if (entity_type == "street_luminaire" || entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") {
- if (method == "set_command") {
-
- //let command = data.params.command;
- let value = data.params.payload.value;
-
- if (command == "dimming") {
-
- let nodeWasFound = false;
- let keys = Object.keys(nodesData);
-
- //logger.debug("-----", keys);
-
- for (let i = 0; i < keys.length; i++) {
- let node = keys[i];
- //logger.debug( node, nodesData[node], tbname);
-
- if (tbname == nodesData[node].tbname) {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- value = parseInt(value);
- if (value > 0) value = value + 128;
-
- params.type = "node-onetime-write";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;
- params.recipient = 1;
- params.byte4 = value;
- params.rw = 1;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'set dimming from platform';
- //params.debug = true;
-
- //debug(params);
- logger.debug("dimming", params);
-
- tasks.push(params);
-
- setTimeout(function() {
-
- //spustime o 4 sekundy neskor, s prioritou PRIORITY_TYPES.high_priority
- //a pridame aj vyreportovanie dimmingu
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read dimming (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //pridame aj vyreportovanie - vykon
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 76;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read Input Power (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //pridame aj vyreportovanie - prud svietidla
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 75;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read Input Current (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //pridame aj vyreportovanie - power faktor - ucinnik
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 77;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read power factor (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- }, 4000);
-
- nodeWasFound = true;
- break;
- }
- }
-
- if (!nodeWasFound) {
- logger.debug("set dimming from platform", "unable to find tbname", tbname);
- }
- }
- else {
- instance.send(SEND_TO.debug, "undefined command " + command);
- logger.debug("undefined command", command);
- }
-
- return;
- }
- else if (method == "set_profile") {
- //nastav profil nodu
- logger.debug("-->set_profile for node", data.params);
- logger.debug("------profile data", profile);
- //instance.send(SEND_TO.debug, "set_profile" + command);
-
- let keys = Object.keys(nodesData);
- for (let i = 0; i < keys.length; i++) {
- let node = keys[i];
- if (tbname == nodesData[node].tbname) {
-
- if (profile != "") profile = JSON.stringify(profile);
- dbNodes.modify({ processed: false, profile: profile }).where("node", node).make(function(builder) {
-
- builder.callback(function(err, response) {
-
- logger.debug("worksys - update node profile done", profile);
- if (profile === "") logger.debug("worksys - update node profile done - profile is empty");
-
- //profil úspešne prijatý pre node č. xx
- sendNotification("Cmd-mngr", tbname, "dimming_profile_was_processed_for_node", { node: node }, profile, SEND_TO.tb, instance);
-
- nodesData[node].processed = false;
- nodesData[node].profile = profile;
-
- processNodeProfile(node);
- });
- });
- }
- }
- }
- else {
-
- instance.send(SEND_TO.debug, "unknown method " + method);
- logger.debug("unknown method", method);
-
- return;
- }
- }
-
- //nastav profil linie z platformy
- else if (entity_type == "edb_line" || entity_type == "edb" || entity_type == "edb_line_ver4" || entity_type == "edb_ver4_se") {
- //profil linie
- //relays.table line:number|tbname:string|contactor:number|profile:string
- //najdeme line relaysData
-
- if (method == "set_profile") {
-
- logger.debug("-->set_profile for line", data.params);
- logger.debug("profile data:", profile);
-
- let keys = Object.keys(relaysData);
- for (let i = 0; i < keys.length; i++) {
- let line = keys[i];
- if (tbname == relaysData[line].tbname) {
- //zmazeme tasky
- removeTask({ type: "relay", line: line });
-
- if (profile != "") profile = JSON.stringify(profile);
- dbRelays.modify({ profile: profile }).where("line", line).make(function(builder) {
-
- builder.callback(function(err, response) {
-
- //update profile
- logger.debug("worksys - update relay profile done:", profile);
- instance.send(SEND_TO.debug, "worksys - update relay profile done");
-
- relaysData[line].profile = profile;
-
- loadRelaysData(line)
- logger.debug("loadRelaysData DONE for line", line);
-
- buildTasks({ processLineProfiles: true, line: line });
-
- sendNotification("Cmd-mngr: set profile from worksys", tbname, "switching_profile_was_processed_for_line", { line: line }, profile, SEND_TO.tb, instance);
- });
- });
- break;
- }
- }
- }
- else if (method == "set_command") {
- let value = data.params.payload.value;
-
- if (command === "switch") {
-
- // if we receive rpc from platform, to switch maintenance mode, we set SETTINGS.maintenance_mode flow variable to value;
- if (entity_type === "edb" || entity_type === "edb_ver4_se") SETTINGS.maintenance_mode = value;
+ return ad.getTime() - bd.getTime();
+ });
- const relayObject = getObjectByTbValue(relaysData, tbname);
- let line = 0;
- if (isObject(relayObject)) line = relayObject.line;
+ console.log("line timepoints ........", time_points);
- // v relaysData je contactor bud 0 alebo 1, ale z platformy prichadza true, false;
- if (value == false) turnLine("off", line, "command received from platform");
- else turnLine("on", line, "command received from platform");
- }
- }
- else {
- instance.send(SEND_TO.debug, "undefined method " + method);
- logger.debug("undefined method", method);
- }
+ let currentValue = 0;
+ if (time_points.length > 0) currentValue = time_points[time_points.length - 1].value;
- return;
- }
- else {
- instance.send(SEND_TO.debug, "UNKNOW entity_type " + entity_type);
- logger.debug("UNKNOW entity_type", entity_type);
- }
- return;
- }
+ monitor.info("-->comming events turn on/off lines:");
+ for (let t = 0; t < time_points.length; t++) {
- //terminal
- if (!rsPort.isOpen) await rsPort.open();
+ let start_time = new Date();
+ let [hours, minutes] = time_points[t].start_time.split(':');
+ start_time.setHours(parseInt(hours), parseInt(minutes), 0);
- let params = flowdata.data.body;
- if (params == undefined) {
- //logger.debug("Cmd-mngr: flowdata.data.body is undefined");
- return;
- }
+ //task is in the past
+ if (now.getTime() > start_time.getTime()) {
+ currentValue = time_points[t].value;
- params.priority = PRIORITY_TYPES.terminal;
- params.type = "cmd-terminal";
- params.tbname = "";
- params.timestamp = PRIORITY_TYPES.terminal;
- params.addMinutesToTimestamp = 0;// do not repeat task!!!
- params.debug = true;
+ //timepoint is in past, we add 24 hours
+ start_time.setDate(start_time.getDate() + 1);
+ }
+
+ let params = getParams();
+ params.type = "relay";
+ params.line = parseInt(line);
+ params.value = time_points[t].value;
+ params.tbname = relaysData[line].tbname;
+ params.timestamp = start_time.getTime();
+
+ // it timepoints are not calculated (dawn, dusk, lux_timepoint), but static points in line profile, we just repeat the task every day
+ if (time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24 * 60;
+
+ //astro timepoints will be recalculated dynamically:
+ params.timePointName = time_points[t].name;
+
+ // if astro timepoint, we save time window:
+ if (['luxOn', 'luxOff', 'dusk', 'dawn'].includes(params.timePointName)) {
+ params.dawn_lux_sensor_time_window = profile.dawn_lux_sensor_time_window;
+ params.dusk_lux_sensor_time_window = profile.dusk_lux_sensor_time_window;
+ }
+
+ if (params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line;
+ else if (params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line;
+
+ params.debug = true;
+
+ //turn on/off line
+ tasks.push(params);
+ monitor.info("TimePoint params: ", params.info, start_time);
+ }
+
+ monitor.info("-->time_points final", line, time_points);
+
+ //ensure to turn on/off according to calculated currentValue
+ let params = getParams();
+ params.type = "relay";
+ params.line = parseInt(line);
+ params.tbname = relaysData[line].tbname;
+ params.value = currentValue;
+ params.timestamp = i;
+ params.debug = true;
+
+ //logger.debug(now.toLocaleString("sk-SK"));
+ monitor.info("-->currentValue for relay", line, currentValue);
+
+ //turn on/off line
+ if (params.value == 0) params.info = "turn off line on startup: " + line;
+ else if (params.value == 1) params.info = "turn on line on startup: " + line;
+
+ tasks.push(params);
+
+ } catch (error) {
+ if (profilestr !== "") {
+ //errLogger.error(profilestr, error);
+ console.log(`Cmd_manager: Unable to process line profile ${line}. Error: `, error);
+ errorHandler.sendMessageToService(profilestr + "-" + error, 0, "js_error");
+ } else {
+ turnLine("off", line, "No line profile. Switching it off on startup");
+ }
+ }
- let timestamp = Date.now();
- params.refFlowdataKey = timestamp;
- //params.refFlowdata = flowdata;
- //refFlowdata = flowdata;
+ }
+ //logger.debug("tasks:");
+ //logger.debug(tasks);
+ }
- //console.log("flowdata", flowdata);
- cleanUpRefFlowdataObj();
+ //NOTE: PROCESS DEFAULT BROADCASTS - Time of dusk, Time of dawn, Actual Time
+ if (processBroadcast) {
- refFlowdataObj[timestamp] = flowdata;
+ let d = new Date();
+ let time = d.getTime();
+ let sunCalcResult = calculateDuskDawn();
+
+ {
+ let params = getParams();
+
+ params.address = 0xffffffff;//broadcast
+ params.byte1 = sunCalcResult["dusk_hours"];
+ params.byte2 = sunCalcResult["dusk_minutes"];
+ params.recipient = 2;//2 broadcast,
+ params.register = 6;//Time of dusk
+ params.rw = 1;//write
+ params.type = "node-regular-write";
+ params.timestamp = time + 60000;
+ params.addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk
+ params.info = "Broadcast-duskTime";
+
+ tasks.push(params);
+ }
+
+ {
+ let params = getParams();
+
+ params.address = 0xffffffff;//broadcast
+ params.byte1 = sunCalcResult["dawn_hours"];
+ params.byte2 = sunCalcResult["dawn_minutes"];
+ params.recipient = 2; //2 broadcast
+ params.register = 7;//Time of dawn
+ params.rw = 1;//write
+ params.type = "node-regular-write";
+ params.timestamp = time + 60001;
+ params.addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn
+ params.info = "Broadcast-dawnTime";
+
+ tasks.push(params);
+ }
+
+ {
+ let params = getParams();
+
+ params.address = 0xffffffff;//broadcast
+ params.byte1 = d.getHours();
+ params.byte2 = d.getMinutes();
+ params.recipient = 2; //2 broadcast
+ params.register = 87;//Actual time
+ params.rw = 1;//write
+ params.type = "node-regular-write";
+ params.timestamp = time + 60002;
+ params.addMinutesToTimestamp = 5;
+ params.info = "run broadcast: Actual time";
+
+ tasks.push(params);
+ }
+
+ }
+
+ //process nodes & tasks - read node's data
+ if (processNodes) {
+
+ let time = Date.now();
+
+ for (let k in nodesData) {
+ let address = parseInt(k);
+ let tbname = nodesData[k].tbname;
+ let register = 0;
+
+ for (let i = 0; i < listOfCommands.length; i++) {
+
+ register = listOfCommands[i];
+ let addMinutesToTimestamp = priorities[register];
+
+ let params = getParams();
+
+ params.address = address;
+ params.recipient = 1;
+ params.register = register;
+ params.type = register == 1 ? "node-dimming-read" : "node-regular-read";
+ params.tbname = tbname;
+ params.timestamp = time + 5000 + i * 500 + addMinutesToTimestamp * 1000; //to make slight time difference
+ params.addMinutesToTimestamp = addMinutesToTimestamp;
+ params.info = "Node regular read command";
+
+ tasks.push(params);
+ }
+
+ }
+ }
+
+
+ //niektore ulohy sa vygeneruju iba 1x pri starte!!!
+ if (!init) return;
+
+
+ //Master node FW version - modifies SETTINGS.masterNodeIsResponding
+ {
+ let params = getParams();
+ params.type = "cmd-master";
+ params.register = 4;
+ params.address = 0;
+ params.timestamp = 0;
+ params.addMinutesToTimestamp = 5;
+ params.tbname = SETTINGS.rvoTbName;
+ params.info = "Master node FW verzia";
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //kazdu hodinu skontrolovat nastavenie profilov
+ {
+ let params = getParams();
+ params.type = "process_profiles";
+ params.timestamp = Date.now() + 60001;
+ params.addMinutesToTimestamp = 60;//60 = every hour
+ params.info = "detekcia nespracovaných profilov linie a nodov";
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ monitor.info("tasks created:", tasks.length);
+ }
+
+
+ /**
+ * We process line profile, where "astro_clock": true
+ * example profile:
+ *
+ "dawn_lux_sensor": true,
+ "dusk_lux_sensor": true,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_value": 5,
+ "dawn_astro_clock_offset": 0,
+ "dusk_astro_clock_offset": 10,
+ "dawn_lux_sensor_time_window": 30,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_astro_clock_time_window": 60,
+ "dusk_astro_clock_time_window": 60
+
+ * if dawn: if currentTimestamp is in timewindow "dawnTime + and - dawn_lux_sensor_time_window" and lux value >= lux_sensor_value, we switch off the line.
+ * if dusk: we do oposite
+ *
+ * dawn: usvit - lux je nad hranicou - vypnem
+ * dusk: sumrak - lux je pod hranicou - zapnem
+ */
+ function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) {
+
+ let now = new Date();
+ let currentTimestamp = now.getTime();
+ let keys = Object.keys(relaysData);
+
+ for (let i = 0; i < keys.length; i++) {
+
+ let line = keys[i]; //line is turned off by default
+ let profilestr = relaysData[line].profile;
+ const contactor = relaysData[line].contactor;
+
+ try {
+
+ let profile = JSON.parse(profilestr);
+ if (Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined");
+
+ if (profile.astro_clock == true) {
+ let sunCalcResult = calculateDuskDawn(now, line);
+
+ //usvit
+ if (profile.dawn_lux_sensor == true) {
+ let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
+ let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60);
+
+ if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
+ if (lux_sensor_value > profile.dawn_lux_sensor_value) {
+ if (contactor) turnLine("off", line, "Profile: dawn - turnOff line according to lux sensor");
+ }
+ }
+ }
+
+ //sumrak
+ if (profile.dusk_lux_sensor == true) {
+ let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
+ let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
+
+ if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
+ if (lux_sensor_value < profile.dusk_lux_sensor_value) {
+ if (!contactor) turnLine("on", line, "Profile: dusk - turnOn line according to lux sensor");
+ }
+ }
+ }
+
+ }
+
+ } catch (error) {
+ if (profilestr !== "") monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error);
+ }
+
+ }
+
+ }
+
+ /**
+ * function updates status and time_of_last_communication of node in the dbNodes
+ * it only updates if conditions are met
+ * it only updates time_of_last_communication of node, if the last written time was more than 10 minutes ago (600000 miliseconds)
+ * if newStatus of node is always receiving false, and it is already for more than SETTINGS.node_status_nok_time value, we update status to "NOK" in tb
+ * function returns true, if status of node needs to be updated in TB (newStatus attribute is false in this case).
+ */
+ function updateNodeStatus(node, newStatus) {
+ //MASTER
+ if (node == 0) return;
+
+ let nodeObj = nodesData[node];
+ if (nodeObj == undefined) return;
+
+ let nodeCurrentStatus = nodeObj.status;
+ const now = Date.now();
+
+ let data = null;
+
+ if (nodeCurrentStatus === "OFFLINE") {
+ data = { status: newStatus };
+ nodeDbStatusModify(node, data);
+ return;
+ }
+ else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication > now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) return;
+ else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication < now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) {
+ data = { time_of_last_communication: now };
+ nodeDbStatusModify(node, data);
+ return;
+ }
+ else if (newStatus == false && nodeCurrentStatus == false) return true;
+ else if (newStatus == false && nodeCurrentStatus == true) {
+ if (nodeObj.time_of_last_communication + SETTINGS.node_status_nok_time > now) return;
+ else {
+ data = { status: newStatus };
+ nodeDbStatusModify(node, data);
+ return true;
+ }
+ }
+ else if (newStatus == true && nodeCurrentStatus == false) {
+ data = { status: newStatus, time_of_last_communication: now };
+ nodeDbStatusModify(node, data);
+ return;
+ }
+
+ }
+
+
+ function nodeDbStatusModify(node, data) {
+ dbNodes.modify(data).where("node", node).callback(function(err, response) {
+ if (!err) {
+ nodesData[node] = { ...nodesData[node], ...data };
+ }
+ });
+ }
+
+
+ async function runTasks() {
+
+ clearInterval(interval);
+
+ let currentTimestamp = Date.now();
+
+ //report dusk, dawn---------------------------------
+ if (reportDuskDawn.dusk_time < currentTimestamp) {
+ //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
+ if ((currentTimestamp - reportDuskDawn.dusk_time) < 60 * 1000) {
+ //reportovali sme?
+ if (reportDuskDawn.dusk_time_reported != sunCalcResult.dusk_time) {
+ //sendNotification("CMD Manager: calculated Time of dusk", SETTINGS.rvoTbName, "dusk_has_occured", { value: sunCalcResult["dusk"] }, "", SEND_TO.tb, instance);
+ reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time;
+ }
+ }
+
+ var nextDay = new Date();
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ sunCalcResult = calculateDuskDawn(nextDay);
+ reportDuskDawn.dusk_time = sunCalcResult.dusk_time;
+ }
+
+ if (reportDuskDawn.dawn_time < currentTimestamp) {
+ //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
+ if ((currentTimestamp - reportDuskDawn.dawn_time) < 60 * 1000) {
+ //reportovali sme?
+ if (reportDuskDawn.dawn_time_reported != sunCalcResult.dawn_time) {
+ //sendNotification("CMD Manager: calculated Time of dawn", SETTINGS.rvoTbName, "dawn_has_occured", { value: sunCalcResult["dawn"] }, "", SEND_TO.tb, instance);
+ reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time;
+ }
+ }
+
+ var nextDay = new Date();
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ sunCalcResult = calculateDuskDawn(nextDay);
+ reportDuskDawn.dawn_time = sunCalcResult.dawn_time;
+
+ }
+ //--------------------------------------------------------
+
+ //sort tasks based on timestamp
+ tasks.sort(function(a, b) {
+ if (a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp) {
+ return a.priority - b.priority;
+ }
+ return a.timestamp - b.timestamp;
+ });
+
+ if (tasks.length == 0) {
+ instance.send(SEND_TO.debug, "no tasks created");
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ if (!rsPort.isOpen) {
+ instance.send(SEND_TO.debug, "!rsPort.isOpen");
+ //await rsPort.open();
+ //console.log("Cmd_manager - !rsPort.isOpen");
+ }
+
+ let currentTask = tasks[0];
+
+ if (currentTask.debug) {
+ //logger.debug("--->task to process", currentTask);
+ }
+
+ if (currentTask.timestamp <= currentTimestamp) {
+ let params = { ...tasks[0] };
+
+ //allow terminal commands
+ if (SETTINGS.maintenance_mode && params.type !== "cmd-terminal") {
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ let type = params.type;
+ let tbname = params.tbname;
+ let node = params.address;
+
+ let register = params.register;
+ let line = null;
+ let itIsNodeCommand;
+
+ if (nodesData[node] !== undefined) {
+ line = nodesData[node].line;
+ itIsNodeCommand = true;
+ }
+
+ if (params.line !== undefined) line = params.line;
+
+ if (params.addMinutesToTimestamp > 0 || params.timePointName) {
+ tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
+ } else {
+ tasks.shift();
+ }
+
+ //kontrola nespracovanych profilov nodov
+ if (type == "process_profiles") {
+ //na vsetky zapnutych liniach sa spracuju nespracovane profily nodov
+ loadRelaysData();
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+ return;
+ }
+
+ //relay
+ if (type == "relay") {
+
+ const timePointName = params.timePointName;
+ const value = params.value;
+
+ let date = new Date();
+ date.setDate(date.getDate() + 1);//next day
+
+ let sunCalcResult;
+ if (timePointName) sunCalcResult = calculateDuskDawn(date, params.line);
+
+ if (timePointName == "dawn") {
+ tasks[0].timestamp = sunCalcResult.dawn_time;
+ }
+ else if (timePointName == "dusk") {
+ tasks[0].timestamp = sunCalcResult.dusk_time;
+ }
+ else if (timePointName == "luxOn") {
+ tasks[0].timestamp = sunCalcResult.dusk_time + params.dusk_lux_sensor_time_window * 60000;
+ }
+ else if (timePointName == "luxOff") {
+ tasks[0].timestamp = sunCalcResult.dawn_time + params.dawn_lux_sensor_time_window * 60000;
+ }
+ else if (timePointName == "profileTimepoint") {
+ tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
+ }
+
+ let info = "aplikovany bod profilu";
+ let onOrOff = "";
+ value == 1 ? onOrOff = "on" : onOrOff = "off";
+
+ turnLine(onOrOff, params.line, info);
+
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ if (!SETTINGS.masterNodeIsResponding) {
+ //ak neodpoveda, nebudeme vykonavat ziadne commands, okrem cmd-terminal cmd-master
+ errorHandler.sendMessageToService("Master node is not responding");
+
+ let stop = true;
+
+ if (type === "cmd-terminal" || type === "cmd-master") stop = false;
+ if (stop) {
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+ }
+
+ let contactorStatus = 1;
+ if (relaysData[line] != undefined) contactorStatus = relaysData[line].contactor;
+
+ if (line === 0 || contactorStatus === 0 || FLOW.deviceStatus.state_of_breaker[line] === "Off") {
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ // TODO: -> status offline for rvo if rotary_switch_state is OFF, this is source of errors
+ //check if rotary_switch_state == "Off"
+ // state_of_braker: disconnected = true?
+
+ if (!rsPort.isOpen) {
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ //RE-CALCULATE VALUES
+ //set actual time for broadcast
+ if (register == 87 && params.recipient === 2) {
+ var d = new Date();
+ params.byte1 = d.getHours();//h
+ params.byte2 = d.getMinutes();//m
+ }
+
+ //SET DUSK/DAWN FOR BROADCAST
+ //Time of dusk
+ if (register == 6 && params.recipient === 2) {
+
+ if (type != "cmd-terminal") {
+ let sunCalcResult = calculateDuskDawn();
+ params.byte1 = sunCalcResult["dusk_hours"];//h
+ params.byte2 = sunCalcResult["dusk_minutes"];//m
+ }
+ }
+
+ //Time of dawn
+ if (register == 7 && params.recipient === 2) {
+ if (type != "cmd-terminal") {
+ let sunCalcResult = calculateDuskDawn();
+ params.byte1 = sunCalcResult["dawn_hours"];//h
+ params.byte2 = sunCalcResult["dawn_minutes"];//m
+ }
+ }
+ //-----------------------
+
+ instance.send(SEND_TO.debug, "address: " + node + " register:" + register + "type: " + type);
+
+ var startTime, endTime;
+ startTime = new Date();
+
+ let saveToTb = true;
+ if (!tbname) saveToTb = false;
+
+ let resp = com_generic(node, params.recipient, params.rw, register, params.name, params.byte1, params.byte2, params.byte3, params.byte4);
+ let readBytes = 11;
+ let timeout = 4000;
+
+
+ // await keyword is important, otherwise incorrect data is returned!
+ await writeData(rsPort, resp, readBytes, timeout).then(function(data) {
+
+ //sometimes happens, that status of node changes even if line was turned off and should be offline. To prevent this, we return if line contactor is 0:
+ if (itIsNodeCommand && line && relaysData[line].contactor !== 1) return;
+
+ endTime = new Date();
+ var timeDiff = endTime - startTime;
+
+ //data je array z 11 bytov: 1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data a 2 byty CRC
+ let dataBytes = data.slice(5, 9);
+ let result = detectIfResponseIsValid(data);
+
+ if(register === 79) console.log("node responsee: ", dataBytes);
+ //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
+ let message = result.message; // OK, NOK
+ let message_type = result.type;
+
+ if (params.hasOwnProperty("debug")) {
+ if (params.debug) {
+ console.log("detected response:", result);
+ logger.debug("Cmd-mngr: writeData done " + message_type + " duration: " + timeDiff + " type: " + params.debug, params, result);
+ }
+ }
+
+ let values = {};
+
+ //CMD FINISHED
+ if (message == "OK") {
+
+ updateNodeStatus(node, true);
+
+ //write
+ if (type == "set_node_profile") {
+ let result = cmdCounterResolve(node);
+ if (result == 0) {
+ dbNodes.modify({ processed: true }).where("node", node).callback(function(err, response) {
+
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: node }, "", SEND_TO.tb, instance);
+
+ logger.debug("--> profil úspešne odoslaný na node č. " + node);
+ nodesData[node].processed = true;
+ nodeProfileSendFail.delete(node);
+ });
+ }
+ }
+
+ //parse read response
+ if (params.rw == 0) {
+ values = processResponse(register, dataBytes); //read
+ console.log("command params: ", params.address, register);
+ }
+
+ if (itIsNodeCommand) {
+ values.comm_status = "OK";
+ values.status = "OK";
+ nodesData[node].readout = { ...nodesData[node].readout, ...values };
+ }
+
+ //master node
+ if (node == 0) {
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status");
+ SETTINGS.masterNodeIsResponding = true;
+ if (register == 4) values["edge_fw_version"] = SETTINGS.edge_fw_version;
+ }
+
+ if (params.debug) {
+ //logger.debug("saveToTb", saveToTb, tbname, values);
+ }
+
+ if (saveToTb && type != "node-regular-read") {
+ sendTelemetry(values, tbname);
+ }
+ else {
+ if (type == "cmd-terminal") {
+ terminalCommandResponse(params, "SUCCESS", data);
+ }
+ }
+
+ }
+ else {
+
+ terminalCommandResponse(params, "ERROR", data);
+ handleNokResponseOnRsPort("handleNOK else block", params, itIsNodeCommand, saveToTb);
- //fix
- //params.address = params.adress;
- logger.debug("received from terminal", params);
- logger.debug("date/time:", new Date());
- logger.debug("tasks length:", tasks.length);
+ if (params.hasOwnProperty("debug")) {
+ if (params.debug) {
+ //logger.debug("writeData err: ", error, result, params);
+ logger.debug("writeData err: ", tbname, node, register, values);
+ }
+ }
+
+ //logger.debug(error, result, params);
+ }
+ }).catch(function(reason) {
+
+ //console.log("writeData catch exception", reason);
+ instance.send(SEND_TO.debug, reason);
+
+ terminalCommandResponse(params, "FAILURE", null, reason);
+ handleNokResponseOnRsPort("handleNOK catch block", params, itIsNodeCommand, saveToTb);
+
+ if (params.hasOwnProperty("debug")) {
+ if (params.debug) {
+ logger.debug("-->WRITE FAILED: " + reason, params.debug, params);
+ }
+ }
+
+ });
+
+ }
+ else {
+ if (currentTask.debug) {
+ // currentTask.timestamp <= currentTimestamp && logger.debug("currentTask is not processed - task is in the future", currentTask);
+ }
+
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ //console.log("----->runTasks - setInterval", new Date());
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+ }
+
+
+ function handleNokResponseOnRsPort(message, params, itIsNodeCommand, saveToTb) {
+
+ let node = params.address;
+ let register = params.register;
+ let type = params.type;
+ let tbName = params.tbname;
+ if (!tbName) return;
+
+ let values = {};
+
+ let updateStatus = updateNodeStatus(node, false);
+
+ if (itIsNodeCommand) {
+ values.comm_status = "NOK";
+ nodesData[node].readout.comm_status = "NOK";
+ }
+
+ if (updateStatus) {
+ values.status = "NOK";
+ nodesData[node].readout.status = "NOK";
+ }
+
+ if (type === "node-regular-read") return;
+
+ //master node
+ if (node == 0) {
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
+ logger.debug("master_node_is_not_responding", params);
+ SETTINGS.masterNodeIsResponding = false;
+
+ if (register == 4) values["master_node_version"] = "NOK";
+ }
+
+ if (type == "set_node_profile") {
+ delete cmdCounter[node];
+ logger.debug("profil nebol úspešne odoslaný na node č. ", params);
+
+ if (!nodeProfileSendFail.has(node)) {
+ sendNotification("CMD Manager: process cmd", tbName, "configuration_of_dimming_profile_to_node_failed", { node: node }, "", SEND_TO.tb, instance);
+ nodeProfileSendFail.add(node);
+ }
+ }
+
+ // console.log("------",node, register, type, itIsNodeCommand, updateStatus, saveToTb, values);
+ if (saveToTb) {
+ sendTelemetry(values, tbName);
+ }
+
+ }
+
+ function sendNodesData() {
+ Object.keys(nodesData).forEach(node => {
+ if (nodesData[node]["status"] !== "OFFLINE") {
+ sendTelemetry(nodesData[node].readout, nodesData[node].tbname);
+ nodesData[node].readout = {};
+ }
+ })
+ }
+
+
+ /**
+ * function handles requests from terminal
+ * responseType can be "SUCCESS", "ERROR" or "FAILURE", depending on rsPort data.
+ * FAILURE means, that we got into catch block of writeData function.
+ */
+ function terminalCommandResponse(params, responseType, data = null, reason = "") { //success, error, failure
+
+ if (params.refFlowdataKey === undefined) {
+ //console.log("params.refFlowdataKey is undefined", params);
+ return;
+ }
+ else {
+ console.log("params.refFlowdataKey: ", params);
+ }
+
+ let message = null;
+ let type = null;
+
+ switch (responseType) {
+ case "SUCCESS":
+ message = "cmd-terminal SUCCESS";
+ type = "SUCCESS";
+ break;
+ case "ERROR":
+ message = "cmd-terminal FAILED";
+ type = "ERROR";
+ break;
+ case "FAILURE":
+ message = "ERROR WRITE FAILED: " + reason;
+ type = "ERROR";
+ break;
+ default:
+ type = undefined;
+ }
+
+ logger.debug(message);
+ logger.debug(params);
+
+ //make http response
+ let responseObj = {}
+ responseObj["type"] = type;
+
+ if (responseType == "FAILURE") responseObj["message"] = "ERROR WRITE FAILED: " + reason;
+ else responseObj["bytes"] = data;
+
+ let refFlowdata = refFlowdataObj[params.refFlowdataKey]; //holds reference to httprequest flowdata
+ if (refFlowdata) {
+ refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, refFlowdata);
+ }
+ }
+
+
+ /**
+ * function handles tasks, that are not needed to run through masterNode. To make them run smooth without waiting for other tasks to be completed, we moved them in separate function
+ */
+ function reportEdgeDateTimeAndNumberOfLuminaires() {
+
+ //Number of ok and nok nodes on platform does not equals to total number of nodes.
+ //possible error is, that nodesData object is changing all the time. To make a proper calculation of ok,nok luminaires, we make a copy of it:
+ let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
+
+ const ts = Date.now();
+ const keys = Object.keys(nodesData_clone);
+
+ const number_of_luminaires = keys.length;
+ let number_of_ok_luminaires = 0;
+ let number_of_nok_luminaires = 0;
+
+ for (let i = 0; i < keys.length; i++) {
+ let key = keys[i];
+ let nodeObj = nodesData_clone[key];
+ if (nodeObj.tbname == undefined) continue;
+
+ if (nodeObj.status === "OFFLINE") {
+ nodeObj.node_status_before_offline === true ? number_of_ok_luminaires++ : number_of_nok_luminaires++;
+ }
+ else if (nodeObj.status == true) number_of_ok_luminaires++;
+ else number_of_nok_luminaires++;
+
+ }
+
+ const values = {
+ "number_of_luminaires": number_of_luminaires,
+ "number_of_ok_luminaires": number_of_ok_luminaires,
+ "number_of_nok_luminaires": number_of_nok_luminaires,
+ "edge_date_time": ts - ts % 60000 //round to full minute
+ };
+
+ sendTelemetry(values, SETTINGS.rvoTbName, ts);
+ }
+
+
+ function handleRsPort() {
+
+ console.log("cmd_man: handleRsPort called");
+ //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
+ // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
+ // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
+
+ if (SETTINGS.serial_port == "" || SETTINGS.serial_port == undefined || SETTINGS.serial_port.length === 1) SETTINGS.serial_port = "ttymxc4";
+ console.log('SETTINGS.serial_port', SETTINGS.serial_port);
+ //rsPort = new SerialPort({path: `/dev/${SETTINGS.serial_port}`, baudRate: 57600, autoOpen: false });
+ rsPort = new SerialPort({ path: "/dev/ttyUSB0", baudRate: 9600, autoOpen: false });
+ //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
+ //rsPort.setMaxListeners(0);
+
+ rsPort.on('open', async function() {
+
+ logger.debug("CMD manager - rsPort opened success");
+ console.log("CMD manager - rsPort opened success");
+
+ await runSyncExec(`stty -F /dev/${SETTINGS.serial_port} 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke`).then(function(status) {
+ instance.send(SEND_TO.debug, "RPC runSyncExec - Promise Resolved:" + status);
+
+ logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status);
+
+ }).catch(function(reason) {
+ instance.send(SEND_TO.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason);
+ console.log("cmd_man: rsport error", reason);
+ });
+ });
+
+ rsPort.on('error', function(err) {
+
+ //TODO report to service!!!
+ //errLogger.error(exports.title, "unable to open port", SETTINGS.serial_port, err.message);
+ errorHandler.sendMessageToService([exports.title, "unable to open port", SETTINGS.serial_port, err.message], 0);
+ console.log("cmd_manager: unable to open rsport", SETTINGS.serial_port, err.message);
+ instance.send(SEND_TO.debug, err.message);
+ });
+
+ rsPort.on("close", () => {
+ setTimeout(() => rsPort.open(), 1000);
+ });
+
+
+ rsPort.open(function(err) {
+ if (err) console.log('rsport open error', err);
+ })
+ }
+
+
+ instance.on("close", () => {
+ clearInterval(interval);
+ clearInterval(customTasksInterval);
+ clearInterval(setCorrectTime);
+ clearInterval(sendNodeReadout);
+ clearInterval(accelerometerInterval);
+ rsPort.close();
+ });
+
+ instance.on("0", _ => {
+ main();
+ })
+
+ instance.on("1", async function(flowdata) {
+
+ //instance.send(SEND_TO.debug, "on Data");
+ //instance.send(SEND_TO.debug, flowdata);
+
+ //logger.debug(flowdata.data);
+
+ //just testing functions
+ if (flowdata.data == "open") {
+ if (!rsPort.isOpen) rsPort.open();
+ return;
+ }
+ else if (flowdata.data == "close") {
+ rsPort.close();
+ return;
+ }
+ else if (flowdata.data == "clean") {
+ tasks = [];
+ return;
+ }
+ else if (flowdata.data == "buildtasks") {
+ //build & run
+ return;
+ }
+ else if (flowdata.data == "run") {
+ //durations = [];
+
+ if (tasks.length == 0) {
+
+ buildTasks();
+
+ if (rsPort.isOpen) {
+ interval = setInterval(runTasks, 100);
+ }
+ else {
+ instance.send(SEND_TO.debug, "port is not opened!!!");
+ }
+ }
+ }
+ else {
+ //terminal data - object
+ //logger.debug("flowdata", flowdata.data);
+
+ if (typeof flowdata.data === 'object') {
+ //logger.debug("dido", flowdata.data);
+ if (flowdata.data.hasOwnProperty("sender")) {
+ //data from dido_controller
+ if (flowdata.data.sender == "dido_controller") {
+
+ if (flowdata.data.hasOwnProperty("cmd")) {
+ let cmd = flowdata.data.cmd;
+
+ if (cmd == "buildTasks") {
+ clearInterval(interval);
+
+ logger.debug("-->CMD MANAGER - BUILD TASKS");
+ buildTasks();
+
+ //logger.debug("tasks:");
+ //logger.debug(tasks);
+
+ logger.debug("-->CMD MANAGER - RUN TASKS");
+ interval = setInterval(runTasks, 5000);
+ }
+ else if (cmd == "reload_relays") {
+ loadRelaysData(flowdata.data.line);
+
+ if (flowdata.data.dataChanged) {
+ if (!flowdata.data.value) {
+ reportOfflineNodeStatus(flowdata.data.line);
+ }
+ else {
+ reportOnlineNodeStatus(flowdata.data.line);
+ }
+ }
+
+ }
+ else if (cmd == "rotary_switch_state") {
+ let value = flowdata.data.value;
+
+ //state was changed
+ if (rotary_switch_state != value) {
+ if (value == "Off") {
+ //vyreportovat vsetky svietdla
+ reportOfflineNodeStatus();
+ }
+
+ rotary_switch_state = value;
+ }
+ }
+ else if (cmd == "lux_sensor") {
+ lux_sensor = parseInt(flowdata.data.value);
+
+ // POSSIBLE SOURCE OF PROBLEMS, IF USER SETS LUX TRESHOLD LEVEL GREATER THAN 100 - WE SHOULD BE CHECKING "DUSK/DAWN_LUX_SENSOR_VALUE" IN PROFILE MAYBE ??
+ if (lux_sensor < 100) {
+
+ // we send lux_sensor value to all nodes:
+ let params = getParams(PRIORITY_TYPES.node_broadcast);
+
+ params.recipient = 2;//2 broadcast, address = 0
+ params.address = 0xffffffff;//Broadcast
+
+ let ba = longToByteArray(lux_sensor);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ params.timestamp = PRIORITY_TYPES.node_broadcast;
+ params.info = "run broadcast: Actual Lux level from cabinet";
+ params.register = 95;//Actual Lux level from cabinet
+ params.rw = 1;//write
+
+ tasks.push(params);
+
+ //process profiles
+ turnOnOffLinesAccordingToLuxSensor(lux_sensor);
+ }
+ }
+ else if (cmd == "state_of_breaker") {
+ //istic linie
+ let value = flowdata.data.value;
+ let line = parseInt(flowdata.data.line);
+
+ let dataChanged = false;
+ if (state_of_breaker[line] != value) dataChanged = true;
+
+ state_of_breaker[line] = value;
- //tasks = [];
+ let status = "OK";
+ if (value == "Off") status = "NOK";
+
+ if (dataChanged) {
+
+ if (relaysData.hasOwnProperty(line)) {
+ let tbname = relaysData[line].tbname;
+
+ if (value == "Off") sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_off_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
+ else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
+
+ //report status liniu
+ sendTelemetry({ status: status }, tbname)
+
+ //current value
+ if (value == "Off") reportOfflineNodeStatus(line); //vyreportovat vsetky svietidla na linii
+ }
+
+ }
+ }
+ else {
+ logger.debug("undefined cmd", cmd);
+ }
+ }
+ }
+
+ return;
+ }
+
+ //data from worksys
+ if (flowdata.data.hasOwnProperty("topic")) {
+
+ let data = getNested(flowdata.data, "content", "data");
+
+ //if we get temperature in senica from senica-prod01
+ let temperature = getNested(flowdata.data, "content", "senica_temperature");
+
+ if (temperature !== undefined) {
+ temperatureInSenica = temperature;
+ return;
+ }
+
+ if (data === undefined) {
+ console.log("Invalid rpc command came from platform");
+ return;
+ }
+
+ let command = data.params.command;
+ let method = data.method;
+ let profile = data.params.payload;
+ if (profile == undefined) profile = "";
+ let entity = data.params.entities[0];
+ let entity_type = entity.entity_type;
+ let tbname = entity.tb_name;
+
+ instance.send(SEND_TO.debug, flowdata.data);
+ logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method);
+ logger.debug("----------------------------");
+
+ if (entity_type == "street_luminaire" || entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") {
+ if (method == "set_command") {
+
+ //let command = data.params.command;
+ let value = data.params.payload.value;
+
+ if (command == "dimming") {
+
+ let nodeWasFound = false;
+ let keys = Object.keys(nodesData);
+
+ //logger.debug("-----", keys);
+
+ for (let i = 0; i < keys.length; i++) {
+ let node = keys[i];
+ //logger.debug( node, nodesData[node], tbname);
+
+ if (tbname == nodesData[node].tbname) {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ value = parseInt(value);
+ if (value > 0) value = value + 128;
+
+ params.type = "node-onetime-write";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;
+ params.recipient = 1;
+ params.byte4 = value;
+ params.rw = 1;
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'set dimming from platform';
+ //params.debug = true;
+
+ //debug(params);
+ logger.debug("dimming", params);
+
+ tasks.push(params);
+
+ setTimeout(function() {
+
+ //spustime o 4 sekundy neskor, s prioritou PRIORITY_TYPES.high_priority
+ //a pridame aj vyreportovanie dimmingu
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;
+ params.recipient = 1;
+ params.rw = 0;
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read dimming (after set dimming from platform)';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //pridame aj vyreportovanie - vykon
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 76;
+ params.recipient = 1;
+ params.rw = 0;
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read Input Power (after set dimming from platform)';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //pridame aj vyreportovanie - prud svietidla
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 75;
+ params.recipient = 1;
+ params.rw = 0;
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read Input Current (after set dimming from platform)';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //pridame aj vyreportovanie - power faktor - ucinnik
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "node-onetime-read";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 77;
+ params.recipient = 1;
+ params.rw = 0;
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read power factor (after set dimming from platform)';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ }, 4000);
+
+ nodeWasFound = true;
+ break;
+ }
+ }
+
+ if (!nodeWasFound) {
+ logger.debug("set dimming from platform", "unable to find tbname", tbname);
+ }
+ }
+ else {
+ instance.send(SEND_TO.debug, "undefined command " + command);
+ logger.debug("undefined command", command);
+ }
+
+ return;
+ }
+ else if (method == "set_profile") {
+ //nastav profil nodu
+ logger.debug("-->set_profile for node", data.params);
+ logger.debug("------profile data", profile);
+ //instance.send(SEND_TO.debug, "set_profile" + command);
+
+ let keys = Object.keys(nodesData);
+ for (let i = 0; i < keys.length; i++) {
+ let node = keys[i];
+ if (tbname == nodesData[node].tbname) {
+
+ if (profile != "") profile = JSON.stringify(profile);
+ dbNodes.modify({ processed: false, profile: profile }).where("node", node).callback(function(err, response) {
+
+ logger.debug("worksys - update node profile done", profile);
+ if (profile === "") logger.debug("worksys - update node profile done - profile is empty");
+
+ //profil úspešne prijatý pre node č. xx
+ sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", { node: node }, profile, SEND_TO.tb, instance);
+
+ nodesData[node].processed = false;
+ nodesData[node].profile = profile;
+
+ processNodeProfile(node);
+ });
+ }
+ }
+ }
+ else {
+
+ instance.send(SEND_TO.debug, "unknown method " + method);
+ logger.debug("unknown method", method);
+
+ return;
+ }
+ }
+
+ //nastav profil linie z platformy
+ else if (entity_type == "edb_line" || entity_type == "edb" || entity_type == "edb_line_ver4" || entity_type == "edb_ver4_se") {
+ //profil linie
+ //relays.table line:number|tbname:string|contactor:number|profile:string
+ //najdeme line relaysData
+
+ if (method == "set_profile") {
+
+ logger.debug("-->set_profile for line", data.params);
+ logger.debug("profile data:", profile);
+
+ let keys = Object.keys(relaysData);
+ for (let i = 0; i < keys.length; i++) {
+ let line = keys[i];
+ if (tbname == relaysData[line].tbname) {
+ //zmazeme tasky
+ removeTask({ type: "relay", line: line });
+
+ if (profile != "") profile = JSON.stringify(profile);
+ dbRelays.modify({ profile: profile }).where("line", line).callback(function(err, response) {
+
+ //update profile
+ logger.debug("worksys - update relay profile done:", profile);
+ instance.send(SEND_TO.debug, "worksys - update relay profile done");
+
+ relaysData[line].profile = profile;
+
+ loadRelaysData(line)
+ logger.debug("loadRelaysData DONE for line", line);
+
+ buildTasks({ processLineProfiles: true, line: line });
+
+ sendNotification("CMD manager - set profile from worksys", tbname, "switching_profile_was_processed_for_line", { line: line }, profile, SEND_TO.tb, instance);
+ });
+ break;
+ }
+ }
+ }
+ else if (method == "set_command") {
+ let value = data.params.payload.value;
+
+ if (command === "switch") {
+
+ // if we receive rpc from platform, to switch maintenance mode, we set SETTINGS.maintenance_mode flow variable to value;
+ if (entity_type === "edb" || entity_type === "edb_ver4_se") SETTINGS.maintenance_mode = value;
+
+ const relayObject = getObjectByTbValue(relaysData, tbname);
+ let line = 0;
+ if (isObject(relayObject)) line = relayObject.line;
- //add to tasks
- tasks.push(params);
+ // v relaysData je contactor bud 0 alebo 1, ale z platformy prichadza true, false;
+ if (value == false) turnLine("off", line, "command received from platform");
+ else turnLine("on", line, "command received from platform");
+ }
+ }
+ else {
+ instance.send(SEND_TO.debug, "undefined method " + method);
+ logger.debug("undefined method", method);
+ }
- }
- }
- })
+ return;
+ }
+ else {
+ instance.send(SEND_TO.debug, "UNKNOW entity_type " + entity_type);
+ logger.debug("UNKNOW entity_type", entity_type);
+ }
+ return;
+ }
+ //terminal
+ if (!rsPort.isOpen) await rsPort.open();
- //function gets value of a nested property in an object and returns undefined if it does not exists:
- function getNested(obj, ...args) {
- return args.reduce((obj, level) => obj && obj[level], obj)
- }
+ let params = flowdata.data.body;
+ if (params == undefined) {
+ //logger.debug("CMD manager flowdata.data.body is undefined");
+ return;
+ }
+ params.priority = PRIORITY_TYPES.terminal;
+ params.type = "cmd-terminal";
+ params.tbname = "";
+ params.timestamp = PRIORITY_TYPES.terminal;
+ params.addMinutesToTimestamp = 0;// do not repeat task!!!
+ params.debug = true;
- /**
- * setCorrectTime function runs once per hour
- * If it is 3 o'clock, it sets actual time, which is got from services
- * https://service-prod01.worksys.io/gettime
- * If also detects Read Only Filesystem once a day
- */
- function setCorrectPlcTimeOnceADay() {
+ let timestamp = Date.now();
+ params.refFlowdataKey = timestamp;
+ //params.refFlowdata = flowdata;
+ //refFlowdata = flowdata;
- const currentTime = new Date();
- if (currentTime.getHours() != 3) return;
+ //console.log("flowdata", flowdata);
- RESTBuilder.make(function(builder) {
+ cleanUpRefFlowdataObj();
- if (!builder) return;
+ refFlowdataObj[timestamp] = flowdata;
- builder.method('GET');
- builder.url('http://192.168.252.2:8004/gettime?projects_id=1');
+ //fix
+ //params.address = params.adress;
+ logger.debug("received from terminal", params);
+ logger.debug("date/time:", new Date());
+ logger.debug("tasks length:", tasks.length);
- builder.callback(function(err, response, output) {
+ //tasks = [];
- if (err) {
- console.log(err);
- return;
- }
+ //add to tasks
+ tasks.push(params);
- const res = output.response;
+ }
+ }
+ })
- try {
- const obj = JSON.parse(res);
- let d = new Date(obj.date);
+ //function gets value of a nested property in an object and returns undefined if it does not exists:
+ function getNested(obj, ...args) {
+ return args.reduce((obj, level) => obj && obj[level], obj)
+ }
- const now = new Date();
- let diffInMinutes = now.getTimezoneOffset();
- console.log("---->TimezoneOffset", diffInMinutes);
+ /**
+ * setCorrectTime function runs once per hour
+ * If it is 3 o'clock, it sets actual time, which is got from services
+ * https://service-prod01.worksys.io/gettime
+ * If also detects Read Only Filesystem once a day
+ */
+ function setCorrectPlcTimeOnceADay() {
- if (d instanceof Date) {
+ const currentTime = new Date();
+ if (currentTime.getHours() != 3) return;
- // monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
+ RESTBuilder.make(function(builder) {
- let year = d.getFullYear();
- let month = addZeroBefore(d.getMonth() + 1);
- let day = addZeroBefore(d.getDate());
+ if (!builder) return;
- let hours = addZeroBefore(d.getHours());
- let minutes = addZeroBefore(d.getMinutes());
- let seconds = addZeroBefore(d.getSeconds());
+ builder.method('GET');
+ builder.url('http://192.168.252.2:8004/gettime?projects_id=1');
- let dateStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+ builder.callback(function(err, response, output) {
- exec(`sudo timedatectl set-time "${dateStr}"`, (err, stdout, stderr) => {
- if (err || stderr) {
- console.error(err);
- console.log(stderr);
- console.log(dateStr);
+ if (err) {
+ console.log(err);
+ return;
+ }
- monitor.info("failed timedatectl set-time", err, stderr);
- }
- else {
- monitor.info("setCorrectPlcTimeOnceADay() --> Nastaveny cas na: ", dateStr);
- }
+ const res = output.response;
- });
- }
+ try {
- } catch (error) {
- logger.debug("setCorrectPlcTimeOnceADay - function error", error, res);
- monitor.info("setCorrectPlcTimeOnceADay - function error", error, res);
- }
+ const obj = JSON.parse(res);
+ let d = new Date(obj.date);
- // we detect readOnlyFileSystem once an hour as well
- detectReadOnlyFilesystem();
+ const now = new Date();
- });
- });
+ let diffInMinutes = now.getTimezoneOffset();
+ console.log("---->TimezoneOffset", diffInMinutes);
- }
+ if (d instanceof Date) {
+ // monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
- function detectReadOnlyFilesystem() {
- exec(`sudo egrep " ro,|,ro " /proc/mounts`, (err, stdout, stderr) => {
- if (err || stderr) {
- console.error(err);
- console.log(stderr);
+ let year = d.getFullYear();
+ let month = addZeroBefore(d.getMonth() + 1);
+ let day = addZeroBefore(d.getDate());
- } else {
- //console.log("Read-only", stdout);
+ let hours = addZeroBefore(d.getHours());
+ let minutes = addZeroBefore(d.getMinutes());
+ let seconds = addZeroBefore(d.getSeconds());
- let lines = stdout + "";
- lines = lines.split("\n");
+ let dateStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
- let readOnlyDetected = "";
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("/dev/mmcblk0p2")) {
- readOnlyDetected = lines[i];
- }
- }
+ exec(`sudo timedatectl set-time "${dateStr}"`, (err, stdout, stderr) => {
+ if (err || stderr) {
+ console.error(err);
+ console.log(stderr);
+ console.log(dateStr);
- if (readOnlyDetected !== "") {
- errorHandler.sendMessageToService("Detected: Read-only file system: " + readOnlyDetected);
- monitor.info("Read only filesystem detected");
- }
+ monitor.info("failed timedatectl set-time", err, stderr);
+ }
+ else {
+ monitor.info("setCorrectPlcTimeOnceADay() --> Nastaveny cas na: ", dateStr);
+ }
- }
- });
- }
+ });
+ }
+ } catch (error) {
+ logger.debug("setCorrectPlcTimeOnceADay - function error", error, res);
+ monitor.info("setCorrectPlcTimeOnceADay - function error", error, res);
+ }
+ // we detect readOnlyFileSystem once an hour as well
+ detectReadOnlyFilesystem();
+ });
+ });
+ }
+ function detectReadOnlyFilesystem() {
+ exec(`sudo egrep " ro,|,ro " /proc/mounts`, (err, stdout, stderr) => {
+ if (err || stderr) {
+ console.error(err);
+ console.log(stderr);
+ } else {
+ //console.log("Read-only", stdout);
- ///helper functions
- function sendTelemetry(values, tbname, date = Date.now()) {
- const dataToTb = {
- [tbname]: [
- {
- "ts": date,
- "values": values
- }
- ]
- }
+ let lines = stdout + "";
+ lines = lines.split("\n");
- tbHandler.sendToTb(dataToTb, instance);
- }
+ let readOnlyDetected = "";
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("/dev/mmcblk0p2")) {
+ readOnlyDetected = lines[i];
+ }
+ }
- function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) {
+ if (readOnlyDetected !== "") {
+ errorHandler.sendMessageToService("Detected: Read-only file system: " + readOnlyDetected);
+ monitor.info("Read only filesystem detected");
+ }
- if (date === undefined) date = new Date();
- //if(duskOffset === undefined) duskOffset = 0;
- //if(dawnOffset === undefined) dawnOffset = 0;
+ }
+ });
+ }
- //let line = keys[i];
- let profilestr = "";
- if (relaysData[line] != undefined) profilestr = relaysData[line].profile;
- let result = {};
- var times = SunCalc.getTimes(date, latitude, longitude);
- let dawn = new Date(times.sunrise);//usvit
- let dusk = new Date(times.sunset);//sumrak
- //http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
- //https://mapa.zoznam.sk/zisti-gps-suradnice-m6
- let dusk_astro_clock_offset = duskOffset;//minutes
- let dawn_astro_clock_offset = dawnOffset;//minutes
- try {
+ ///helper functions
+ function sendTelemetry(values, tbname, date = Date.now()) {
+ const dataToTb = {
+ [tbname]: [
+ {
+ "ts": date,
+ "values": values
+ }
+ ]
+ }
- let profile = JSON.parse(profilestr);
- if (Object.keys(profile).length === 0) throw ("profile is not defined");
+ tbHandler.sendToTb(dataToTb, instance);
+ }
- //Jednoduchý režim
- if (profile.astro_clock == false && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false) {
+ function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) {
- }
+ if (date === undefined) date = new Date();
+ //if(duskOffset === undefined) duskOffset = 0;
+ //if(dawnOffset === undefined) dawnOffset = 0;
- //Režim astrohodín
- if (profile.astro_clock == true) {
- //if(profile.dusk_lux_sensor == false)
- {
- if (profile.hasOwnProperty("dusk_astro_clock_offset")) dusk_astro_clock_offset = parseInt(profile.dusk_astro_clock_offset);
- }
+ //let line = keys[i];
+ let profilestr = "";
+ if (relaysData[line] != undefined) profilestr = relaysData[line].profile;
- //if(profile.dawn_lux_sensor == false)
- {
- if (profile.hasOwnProperty("dawn_astro_clock_offset")) dawn_astro_clock_offset = parseInt(profile.dawn_astro_clock_offset);
- }
+ let result = {};
- }
+ var times = SunCalc.getTimes(date, latitude, longitude);
+ let dawn = new Date(times.sunrise);//usvit
+ let dusk = new Date(times.sunset);//sumrak
- //dusk - súmrak
- //down, sunrise - svitanie
- } catch (error) {
- if (profilestr != "") {
- logger.debug(profilestr);
- logger.debug(error);
- }
- }
+ //http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
+ //https://mapa.zoznam.sk/zisti-gps-suradnice-m6
- result.dusk_no_offset = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
- result.dawn_no_offset = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
- dusk = new Date(dusk.getTime() + gmtOffset + dusk_astro_clock_offset * 60000);
- dawn = new Date(dawn.getTime() + gmtOffset + dawn_astro_clock_offset * 60000);
+ let dusk_astro_clock_offset = duskOffset;//minutes
+ let dawn_astro_clock_offset = dawnOffset;//minutes
- result.dusk = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
- result.dusk_hours = dusk.getHours();
- result.dusk_minutes = dusk.getMinutes();
+ try {
- result.dawn = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
- result.dawn_hours = dawn.getHours();
- result.dawn_minutes = dawn.getMinutes();
+ let profile = JSON.parse(profilestr);
+ if (Object.keys(profile).length === 0) throw ("profile is not defined");
- result.dusk_time = dusk.getTime();
- result.dawn_time = dawn.getTime();
+ //Jednoduchý režim
+ if (profile.astro_clock == false && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false) {
- result.dusk_astro_clock_offset = dusk_astro_clock_offset;
- result.dawn_astro_clock_offset = dawn_astro_clock_offset;
+ }
- return result;
- }
+ //Režim astrohodín
+ if (profile.astro_clock == true) {
+ //if(profile.dusk_lux_sensor == false)
+ {
+ if (profile.hasOwnProperty("dusk_astro_clock_offset")) dusk_astro_clock_offset = parseInt(profile.dusk_astro_clock_offset);
+ }
+ //if(profile.dawn_lux_sensor == false)
+ {
+ if (profile.hasOwnProperty("dawn_astro_clock_offset")) dawn_astro_clock_offset = parseInt(profile.dawn_astro_clock_offset);
+ }
- function processResponse(register, bytes) {
-
- let values = {};
-
- let byte3 = bytes[0];
- let byte2 = bytes[1];
- let byte1 = bytes[2];
- let byte0 = bytes[3];
-
- //status
- if (register == 0) {
- let statecode = bytesToInt(bytes);
- values = { "statecode": statecode };
- return values;
- }
-
- //Dimming, CCT
- else if (register == 1) {
- let brightness = 0;
- let dimming = byte0;
- if (dimming > 128) {
- //dimming = -128;
- brightness = dimming - 128;
- }
-
- //cct
- //Ak Byte3 == 1: CCT = (Byte2*256)+Byte1
- let cct;
- if (byte3 == 1) cct = byte2 * 256 + byte1;
- else cct = bytesToInt(bytes.slice(0, 3));
-
- //cct podla auditu
-
- values["dimming"] = brightness;
- return values;
- }
-
- //
- else if (register == 4) {
- values["master_node_version"] = bytes[1] + "." + bytes[2];
- //logger.debug("FW Version", register, bytes);
- }
-
- //Napätie
- else if (register == 74) {
- let voltage = (bytesToInt(bytes) * 0.1).toFixed(1);
- values["voltage"] = Number(voltage);
- }
-
- //Prúd
- else if (register == 75) {
- let current = bytesToInt(bytes);
- values["current"] = current;
- }
-
- //výkon
- else if (register == 76) {
- let power = (bytesToInt(bytes) * 0.1).toFixed(2);
- values["power"] = Number(power);
- }
-
- //účinník
- else if (register == 77) {
- let power_factor = Math.cos(bytesToInt(bytes) * 0.1 * (Math.PI / 180)).toFixed(2);
- values["power_factor"] = Number(power_factor);
- }
-
- //frekvencia
- else if (register == 78) {
- let frequency = (bytesToInt(bytes) * 0.1).toFixed(2);
- values["frequency"] = Number(frequency);
- }
-
- //energia
- else if (register == 79) {
- let energy = bytesToInt(bytes);
- values["energy"] = energy / 1000; //energia v kWh -> delit 1000
- }
-
- //doba života
- else if (register == 80) {
- let lifetime = (bytesToInt(bytes) / 60).toFixed(2);
- values["lifetime"] = Number(lifetime);
- }
-
- //nastavenie profilu
- else if (register == 8) {
- let time_schedule_settings = bytesToInt(bytes);
- values["time_schedule_settings"] = time_schedule_settings;
- }
-
- //naklon - nateraz sa z nodu nevycitava! kvoli problemom s accelerometrom a vracanymi hodnotami, posielame temp a x y z vo funkcii accelerometerData()
- else if (register == 84) {
- values["temperature"] = byte3 >= 128 ? (byte3 - 128) * (-1) : byte3;
- values["inclination_x"] = byte2 >= 128 ? (byte2 - 128) * (-1) : byte2;
- values["inclination_y"] = byte1 >= 128 ? (byte1 - 128) * (-1) : byte1;
- values["inclination_z"] = byte0 >= 128 ? (byte0 - 128) * (-1) : byte0;
- }
-
- //FW verzia nodu
- else if (register == 89) {
- //formát: "Byte3: Byte2.Byte1 (Byte0)"
- values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
- }
-
- else if (register == 87 || register == 6 || register == 7) {
- var d = new Date();
- d.setHours(byte3, byte2, 0, 0);
- let timestamp = d.getTime();
-
- //aktuálny čas
- if (register == 87) values["actual_time"] = timestamp;
- //čas súmraku
- else if (register == 6) values["dusk_time"] = timestamp;
- //čas úsvitu
- else if (register == 7) values["dawn_time"] = timestamp;
- }
-
- return values;
- }
-
-
- //byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
- function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4) {
- let resp = [];
-
- let cmd = register;
-
- if (typeof adresa === 'string') adresa = parseInt(adresa);
- if (typeof byte1 === 'string') byte1 = parseInt(byte1);
- if (typeof byte2 === 'string') byte2 = parseInt(byte2);
- if (typeof byte3 === 'string') byte3 = parseInt(byte3);
- if (typeof byte4 === 'string') byte4 = parseInt(byte4);
-
- if (rw === 0) {
- cmd = cmd + 0x8000;
- }
-
- //master
- if (rec === 0) adresa = 0;
-
- if (rec === 2) {
- adresa = 0xffffffff;//Broadcast
- }
-
- //recipient
- if (rec === 3) {
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(adresa & 0xFF);//band
- }
- else {
- resp.push((adresa >> 24) & 0xFF);//rshift
- resp.push((adresa >> 16) & 0xFF);
- resp.push((adresa >> 8) & 0xFF);
- resp.push(adresa & 0xFF);
-
- if (rec === 2) {
- resp.push(0xFF);
- }
- else resp.push(0);
- }
-
- resp.push((cmd >> 8) & 0xFF);//rshift
- resp.push(cmd & 0xFF);//band
- resp.push(byte1 & 0xFF);//band
- resp.push(byte2 & 0xFF);//band
- resp.push(byte3 & 0xFF);//band
- resp.push(byte4 & 0xFF);//band
+ }
- //let data = '12345';
- let crc = crc16('ARC', resp);
- let c1 = (crc >> 8) & 0xFF;
- let c2 = crc & 0xFF;
+ //dusk - súmrak
+ //down, sunrise - svitanie
- resp.push(c1);
- resp.push(c2);
+ } catch (error) {
+ if (profilestr != "") {
+ logger.debug(profilestr);
+ logger.debug(error);
+ }
+ }
- //logger.debug("checksum", crc);
- //logger.debug("resp", resp);
+ result.dusk_no_offset = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
+ result.dawn_no_offset = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
- return resp;
+ dusk = new Date(dusk.getTime() + gmtOffset + dusk_astro_clock_offset * 60000);
+ dawn = new Date(dawn.getTime() + gmtOffset + dawn_astro_clock_offset * 60000);
- }
+ result.dusk = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
+ result.dusk_hours = dusk.getHours();
+ result.dusk_minutes = dusk.getMinutes();
- function getObjectByTbValue(object, tbname) {
- return object[Object.keys(object).find(key => object[key].tbname === tbname)];
- }
+ result.dawn = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
+ result.dawn_hours = dawn.getHours();
+ result.dawn_minutes = dawn.getMinutes();
- function isObject(item) {
- return (typeof item === "object" && !Array.isArray(item) && item !== null);
- }
+ result.dusk_time = dusk.getTime();
+ result.dawn_time = dawn.getTime();
+ result.dusk_astro_clock_offset = dusk_astro_clock_offset;
+ result.dawn_astro_clock_offset = dawn_astro_clock_offset;
- // we fake data, that should be received from accelerometer, as they are a bit unreliable. (temperature, x,y,z)
- function accelerometerData() {
+ return result;
+ }
- if (temperatureInSenica === null) return;
- //clone nodesData and relaysData objects
- let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
- let relaysData_clone = JSON.parse(JSON.stringify(relaysData));
+ function processResponse(register, bytes) {
+
+ let values = {};
+
+ let byte3 = bytes[0];
+ let byte2 = bytes[1];
+ let byte1 = bytes[2];
+ let byte0 = bytes[3];
+
+ //status
+ if (register == 0) {
+ let statecode = bytesToInt(bytes);
+ values = { "statecode": statecode };
+ return values;
+ }
+
+ //Dimming, CCT
+ else if (register == 1) {
+ let brightness = 0;
+ let dimming = byte0;
+ if (dimming > 128) {
+ //dimming = -128;
+ brightness = dimming - 128;
+ }
+
+ //cct
+ //Ak Byte3 == 1: CCT = (Byte2*256)+Byte1
+ let cct;
+ if (byte3 == 1) cct = byte2 * 256 + byte1;
+ else cct = bytesToInt(bytes.slice(0, 3));
+
+ //cct podla auditu
+
+ values["dimming"] = brightness;
+ return values;
+ }
+
+ //
+ else if (register == 4) {
+ values["master_node_version"] = bytes[1] + "." + bytes[2];
+ //logger.debug("FW Version", register, bytes);
+ }
+
+ //Napätie
+ else if (register == 74) {
+ let voltage = (bytesToInt(bytes) * 0.1).toFixed(1);
+ values["voltage"] = Number(voltage);
+ }
+
+ //Prúd
+ else if (register == 75) {
+ let current = bytesToInt(bytes);
+ values["current"] = current;
+ }
+
+ //výkon
+ else if (register == 76) {
+ let power = (bytesToInt(bytes) * 0.1).toFixed(2);
+ values["power"] = Number(power);
+ }
+
+ //účinník
+ else if (register == 77) {
+ let power_factor = Math.cos(bytesToInt(bytes) * 0.1 * (Math.PI / 180)).toFixed(2);
+ values["power_factor"] = Number(power_factor);
+ }
+
+ //frekvencia
+ else if (register == 78) {
+ let frequency = (bytesToInt(bytes) * 0.1).toFixed(2);
+ values["frequency"] = Number(frequency);
+ }
+
+ //energia
+ else if (register == 79) {
+ let energy = bytesToInt(bytes);
+ console.log("bytesToIng ",bytesToInt(bytes))
+ //Energiu treba reportovať v kWh -> delit 1000
+ values["energy"] = energy / 1000;
+ }
+
+ //doba života
+ else if (register == 80) {
+ let lifetime = (bytesToInt(bytes) / 60).toFixed(2);
+ values["lifetime"] = Number(lifetime);
+ }
+
+ //nastavenie profilu
+ else if (register == 8) {
+ let time_schedule_settings = bytesToInt(bytes);
+ values["time_schedule_settings"] = time_schedule_settings;
+ }
+
+ //naklon - nateraz sa z nodu nevycitava! kvoli problemom s accelerometrom a vracanymi hodnotami, posielame temp a x y z vo funkcii accelerometerData()
+ else if (register == 84) {
+ values["temperature"] = byte3 >= 128 ? (byte3 - 128) * (-1) : byte3;
+ values["inclination_x"] = byte2 >= 128 ? (byte2 - 128) * (-1) : byte2;
+ values["inclination_y"] = byte1 >= 128 ? (byte1 - 128) * (-1) : byte1;
+ values["inclination_z"] = byte0 >= 128 ? (byte0 - 128) * (-1) : byte0;
+ }
+
+ //FW verzia nodu
+ else if (register == 89) {
+ //formát: "Byte3: Byte2.Byte1 (Byte0)"
+ values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
+ }
+
+ else if (register == 87 || register == 6 || register == 7) {
+ var d = new Date();
+ d.setHours(byte3, byte2, 0, 0);
+ let timestamp = d.getTime();
+
+ //aktuálny čas
+ if (register == 87) values["actual_time"] = timestamp;
+ //čas súmraku
+ else if (register == 6) values["dusk_time"] = timestamp;
+ //čas úsvitu
+ else if (register == 7) values["dawn_time"] = timestamp;
+ }
+
+ return values;
+ }
+
+
+ //byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
+ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4) {
+ let resp = [];
+
+ let cmd = register;
+
+ if (typeof adresa === 'string') adresa = parseInt(adresa);
+ if (typeof byte1 === 'string') byte1 = parseInt(byte1);
+ if (typeof byte2 === 'string') byte2 = parseInt(byte2);
+ if (typeof byte3 === 'string') byte3 = parseInt(byte3);
+ if (typeof byte4 === 'string') byte4 = parseInt(byte4);
+
+ if (rw === 0) {
+ cmd = cmd + 0x8000;
+ }
+
+ //master
+ if (rec === 0) adresa = 0;
+
+ if (rec === 2) {
+ adresa = 0xffffffff;//Broadcast
+ }
+
+ //recipient
+ if (rec === 3) {
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(adresa & 0xFF);//band
+ }
+ else {
+ resp.push((adresa >> 24) & 0xFF);//rshift
+ resp.push((adresa >> 16) & 0xFF);
+ resp.push((adresa >> 8) & 0xFF);
+ resp.push(adresa & 0xFF);
+
+ if (rec === 2) {
+ resp.push(0xFF);
+ }
+ else resp.push(0);
+ }
+
+ resp.push((cmd >> 8) & 0xFF);//rshift
+ resp.push(cmd & 0xFF);//band
+ resp.push(byte1 & 0xFF);//band
+ resp.push(byte2 & 0xFF);//band
+ resp.push(byte3 & 0xFF);//band
+ resp.push(byte4 & 0xFF);//band
+
+ //let data = '12345';
+ let crc = crc16('ARC', resp);
+ let c1 = (crc >> 8) & 0xFF;
+ let c2 = crc & 0xFF;
- for (const key in relaysData_clone) {
+ resp.push(c1);
+ resp.push(c2);
- const lineData = relaysData_clone[key];
- const lineNumber = lineData.line;
- const contactor = lineData.contactor;
+ //logger.debug("checksum", crc);
+ //logger.debug("resp", resp);
- if (lineNumber === 0) continue;
+ return resp;
- if (contactor === 1) {
+ }
- let date = Date.now();
+ function getObjectByTbValue(object, tbname) {
+ return object[Object.keys(object).find(key => object[key].tbname === tbname)];
+ }
- Object.keys(nodesData_clone).forEach((node, index) => {
+ function isObject(item) {
+ return (typeof item === "object" && !Array.isArray(item) && item !== null);
+ }
- setTimeout(function() {
- if (nodesData_clone[node].line === lineNumber) {
+ // we fake data, that should be received from accelerometer, as they are a bit unreliable. (temperature, x,y,z)
+ function accelerometerData() {
- // NOTE: if status of luminaire is NOK or OFFLINE, we do not send data;
- let status = nodesData_clone[node].status;
- if (status === "OFFLINE" || !status) return;
+ if (temperatureInSenica === null) return;
- let x = null;
- if (naklony.hasOwnProperty(node)) x = naklony[node].naklon;
- if (x === null) x = 0;
+ //clone nodesData and relaysData objects
+ let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
+ let relaysData_clone = JSON.parse(JSON.stringify(relaysData));
- sendTelemetry({ temperature: Math.round(temperatureInSenica + 10 + Math.floor(Math.random() * 3)), inclination_x: x, inclination_y: 0, inclination_z: 0 }, nodesData_clone[node].tbname, date);
- }
+ for (const key in relaysData_clone) {
- }, (index + 1) * 500);
- })
+ const lineData = relaysData_clone[key];
+ const lineNumber = lineData.line;
+ const contactor = lineData.contactor;
- }
- }
- }
+ if (lineNumber === 0) continue;
+
+ if (contactor === 1) {
+
+ let date = Date.now();
+
+ Object.keys(nodesData_clone).forEach((node, index) => {
+
+ setTimeout(function() {
+
+ if (nodesData_clone[node].line === lineNumber) {
+
+ // NOTE: if status of luminaire is NOK or OFFLINE, we do not send data;
+ let status = nodesData_clone[node].status;
+ if (status === "OFFLINE" || !status) return;
+
+ let x = null;
+ if (naklony.hasOwnProperty(node)) x = naklony[node].naklon;
+ if (x === null) x = 0;
+
+ sendTelemetry({ temperature: Math.round(temperatureInSenica + 10 + Math.floor(Math.random() * 3)), inclination_x: x, inclination_y: 0, inclination_z: 0 }, nodesData_clone[node].tbname, date);
+ }
+
+ }, (index + 1) * 500);
+ })
+
+ }
+ }
+ }
} // end of instance.export
diff --git a/flow/db_init.js b/flow/db_init.js
index 60a0510..2a5caf9 100644
--- a/flow/db_init.js
+++ b/flow/db_init.js
@@ -6,14 +6,33 @@ exports.version = '1.0.2';
exports.icon = 'sign-out';
exports.output = 2;
+exports.html = `
+
+
+
Hostname or IP address (if not empty - setting will override db setting)
+
+
+
+
+
`;
+
+
exports.readme = `
- # DB initialization
+# DB initialization
`;
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
const { initNotification } = require('./helper/notification_reporter');
const errorHandler = require('./helper/ErrorToServiceHandler');
-const total_energy = require('../databases/total_energy');
const SEND_TO = {
db_init: 0,
@@ -22,6 +41,7 @@ const SEND_TO = {
exports.install = async function(instance) {
+
const dbNodes = TABLE("nodes");
const dbRelays = TABLE("relays");
const dbSettings = TABLE("settings");
@@ -50,7 +70,7 @@ exports.install = async function(instance) {
Object.keys(dbs.nodesData).forEach(node => dbs.nodesData[node].readout = {})
dbs.settings = {
- edge_fw_version: "2025-07-08", //rok-mesiac-den
+ edge_fw_version: "2025-04-24", //rok-mesiac-den
language: responseSettings[0]["lang"],
rvo_name: responseSettings[0]["rvo_name"],
project_id: responseSettings[0]["project_id"],
@@ -78,11 +98,6 @@ exports.install = async function(instance) {
maintenance_mode: false,
}
-
- let rvo_number = responseSettings[0]["rvo_name"].match(/\D+(\d{1,2})_/)[1];
- dbs.settings.energy_to_switch_lamps = total_energy[rvo_number];
- if (dbs.settings.energy_to_switch_lamps === undefined) console.log('=============== db_init.js: energy_to_switch_lamps is undefined');
-
FLOW.dbLoaded = true;
errorHandler.setProjectId(dbs.settings.project_id);
initNotification();
diff --git a/flow/designer.json b/flow/designer.json
index 7565777..e5d2a7c 100644
--- a/flow/designer.json
+++ b/flow/designer.json
@@ -36,13 +36,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#DA4453",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#DA4453",
- "notes": ""
+ }
},
{
"id": "1612776786008",
@@ -89,14 +89,14 @@
"text": "Connected",
"color": "green"
},
+ "color": "#888600",
+ "notes": "",
"options": {
"username": "",
"clientid": "",
"port": "1883",
"host": ""
- },
- "color": "#888600",
- "notes": ""
+ }
},
{
"id": "1612778461252",
@@ -129,11 +129,11 @@
"text": "tb-push",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1612783322136",
@@ -144,22 +144,20 @@
"y": 324,
"connections": {},
"disabledio": {
- "input": [
- 0
- ],
+ "input": [],
"output": []
},
"state": {
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1615551060773",
@@ -179,13 +177,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#DA4453",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#DA4453",
- "notes": ""
+ }
},
{
"id": "1615563373927",
@@ -205,13 +203,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#DA4453",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#DA4453",
- "notes": ""
+ }
},
{
"id": "1615566865233",
@@ -229,11 +227,11 @@
"text": "tb-push",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1615798582262",
@@ -253,13 +251,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1615802995322",
@@ -277,13 +275,13 @@
"text": "Disabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": false
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1615809128443",
@@ -301,13 +299,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1615809595184",
@@ -325,11 +323,11 @@
"text": "tb-push",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1616165795916",
@@ -358,6 +356,9 @@
"text": "Listening",
"color": "green"
},
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false,
"options": {
"timeout": 10,
"cachepolicy": 0,
@@ -367,15 +368,12 @@
"method": "POST",
"name": "",
"flags": [
+ 10000,
"id:1616165795916",
- "post",
- 10000
+ "post"
],
"emptyresponse": false
- },
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false
+ }
},
{
"id": "1616165824813",
@@ -393,11 +391,11 @@
"text": "",
"color": "gray"
},
+ "color": "#5D9CEC",
+ "notes": "",
"options": {
"datatype": "json"
- },
- "color": "#5D9CEC",
- "notes": ""
+ }
},
{
"id": "1617104731852",
@@ -417,13 +415,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1617114651703",
@@ -448,12 +446,12 @@
"text": "",
"color": "gray"
},
- "options": {
- "data": "{line: 3, command: \"turnOff\", force: true}",
- "datatype": "object"
- },
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {
+ "datatype": "object",
+ "data": "{line: 2, command: \"off\", force: true}"
+ }
},
{
"id": "1617115013095",
@@ -471,11 +469,11 @@
"text": "tb-push",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1617284749681",
@@ -500,12 +498,12 @@
"text": "",
"color": "gray"
},
- "options": {
- "datatype": "string",
- "data": "profile_nodes"
- },
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {
+ "data": "profile_nodes",
+ "datatype": "string"
+ }
},
{
"id": "1618235171399",
@@ -530,11 +528,11 @@
"text": "",
"color": "gray"
},
+ "color": "#F6BB42",
+ "notes": "",
"options": {
"data": "run"
- },
- "color": "#F6BB42",
- "notes": ""
+ }
},
{
"id": "1618300858252",
@@ -552,13 +550,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1618393583970",
@@ -576,11 +574,11 @@
"text": "from-dido-controller",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "from-dido-controller"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1618393674428",
@@ -605,11 +603,11 @@
"text": "platform-rpc-call",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "platform-rpc-call"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1618393759854",
@@ -638,11 +636,11 @@
"text": "cmd_to_dido",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "cmd_to_dido"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1618393827655",
@@ -660,11 +658,11 @@
"text": "cmd_to_dido",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "cmd_to_dido"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1618558465485",
@@ -682,11 +680,11 @@
"text": "platform-rpc-call",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "platform-rpc-call"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1618572059773",
@@ -711,12 +709,12 @@
"text": "",
"color": "gray"
},
- "options": {
- "datatype": "object",
- "data": "{line: 1, command: \"turnOn\", force: true}"
- },
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {
+ "data": "{line: 2, command: \"on\", force: true}",
+ "datatype": "object"
+ }
},
{
"id": "1619515097737",
@@ -769,9 +767,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#5D9CEC",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1619605019281",
@@ -800,6 +798,9 @@
"text": "Listening",
"color": "green"
},
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false,
"options": {
"timeout": 5,
"cachepolicy": 0,
@@ -809,14 +810,11 @@
"method": "GET",
"name": "",
"flags": [
+ 5000,
"id:1619605019281",
- "get",
- 5000
+ "get"
]
- },
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false
+ }
},
{
"id": "1619784672383",
@@ -841,12 +839,12 @@
"text": "",
"color": "gray"
},
- "options": {
- "data": "{command: \"turnOnAlarm\"}",
- "datatype": "object"
- },
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {
+ "datatype": "object",
+ "data": "{command: \"turnOnAlarm\"}"
+ }
},
{
"id": "1619784812964",
@@ -871,12 +869,12 @@
"text": "",
"color": "gray"
},
- "options": {
- "data": "{command: \"turnOffAlarm\"}",
- "datatype": "object"
- },
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {
+ "datatype": "object",
+ "data": "{command: \"turnOffAlarm\"}"
+ }
},
{
"id": "1621340721628",
@@ -894,11 +892,11 @@
"text": "modbus_to_dido",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "modbus_to_dido"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1622640022885",
@@ -923,6 +921,9 @@
"text": "Listening",
"color": "green"
},
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false,
"options": {
"timeout": 5,
"cachepolicy": 0,
@@ -931,14 +932,11 @@
"url": "/db_connector",
"method": "POST",
"flags": [
+ 5000,
"id:1622640022885",
- "post",
- 5000
+ "post"
]
- },
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false
+ }
},
{
"id": "1622640073521",
@@ -963,11 +961,11 @@
"text": "",
"color": "gray"
},
+ "color": "#2134B0",
+ "notes": "",
"options": {
"edge": "undefined"
- },
- "color": "#2134B0",
- "notes": ""
+ }
},
{
"id": "1622641420685",
@@ -985,9 +983,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#5D9CEC",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1634303504177",
@@ -1009,15 +1007,15 @@
"output": []
},
"state": {
- "text": "840.05 MB / 985.68 MB",
+ "text": "595.82 MB / 982.12 MB",
"color": "gray"
},
+ "color": "#F6BB42",
+ "notes": "",
"options": {
"enabled": true,
"interval": 30000
- },
- "color": "#F6BB42",
- "notes": ""
+ }
},
{
"id": "1634303533779",
@@ -1039,16 +1037,16 @@
"output": []
},
"state": {
- "text": "5.78 GB / 7.26 GB",
+ "text": "3.80 GB / 6.86 GB",
"color": "gray"
},
+ "color": "#F6BB42",
+ "notes": "",
"options": {
"enabled": true,
"path": "/",
"interval": 30000
- },
- "color": "#F6BB42",
- "notes": ""
+ }
},
{
"id": "1634303595494",
@@ -1077,11 +1075,11 @@
"text": "send-to-services",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1634303602169",
@@ -1099,11 +1097,11 @@
"text": "send-to-services",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1634303685503",
@@ -1121,11 +1119,11 @@
"text": "send-to-services",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1634303743260",
@@ -1151,13 +1149,13 @@
"text": "",
"color": "gray"
},
- "options": {
- "stringify": "json",
- "method": "POST",
- "url": "http://192.168.252.2:8004/sentmessage"
- },
"color": "#5D9CEC",
- "notes": ""
+ "notes": "",
+ "options": {
+ "url": "http://192.168.252.2:8004/sentmessage",
+ "method": "POST",
+ "stringify": "json"
+ }
},
{
"id": "1634463186563",
@@ -1177,13 +1175,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1634464580289",
@@ -1212,13 +1210,13 @@
"text": "",
"color": "gray"
},
+ "color": "#656D78",
+ "notes": "",
"options": {
"keepmessage": true,
"code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);",
"outputs": 1
- },
- "color": "#656D78",
- "notes": ""
+ }
},
{
"id": "1634465243324",
@@ -1238,13 +1236,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1634465281992",
@@ -1273,13 +1271,13 @@
"text": "",
"color": "gray"
},
+ "color": "#656D78",
+ "notes": "",
"options": {
"keepmessage": true,
"code": "value.sender = \"ram\";\n\nlet response = {};\n\nresponse.memory_total = Math.round(value.total / (1024 ** 2));\nresponse.memory_free = Math.round(value.free / (1024 ** 2));\nresponse.memory_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
"outputs": 1
- },
- "color": "#656D78",
- "notes": ""
+ }
},
{
"id": "1634465338103",
@@ -1299,13 +1297,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1634465821120",
@@ -1334,13 +1332,13 @@
"text": "",
"color": "gray"
},
+ "color": "#656D78",
+ "notes": "",
"options": {
"keepmessage": true,
"code": "value.sender = \"hdd\";\n\nlet response = {};\n\nresponse.hdd_total = Math.round(value.total / (1024 ** 2));\nresponse.hdd_free = Math.round(value.free / (1024 ** 2));\nresponse.hdd_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
"outputs": 1
- },
- "color": "#656D78",
- "notes": ""
+ }
},
{
"id": "1634465892500",
@@ -1360,13 +1358,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1634484067516",
@@ -1386,13 +1384,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1634488120710",
@@ -1421,11 +1419,11 @@
"text": "",
"color": "gray"
},
+ "color": "#2134B0",
+ "notes": "",
"options": {
"edge": "undefined"
- },
- "color": "#2134B0",
- "notes": ""
+ }
},
{
"id": "1635327431236",
@@ -1445,13 +1443,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1635936391935",
@@ -1469,11 +1467,11 @@
"text": "send-to-services",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1637069803394",
@@ -1495,9 +1493,11 @@
"output": []
},
"state": {
- "text": "2.4% / 74.33 MB",
+ "text": "2.8% / 99.24 MB",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"monitorfiles": true,
"monitorconnections": true,
@@ -1505,9 +1505,7 @@
"monitorconsumption": true,
"enabled": true,
"interval": 30000
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1683664161036",
@@ -1527,13 +1525,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1683981346282",
@@ -1562,11 +1560,11 @@
"text": "from-dido-controller",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "from-dido-controller"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1684055037116",
@@ -1586,13 +1584,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1684060205000",
@@ -1612,13 +1610,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1684179110403",
@@ -1636,13 +1634,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1699963668903",
@@ -1683,11 +1681,11 @@
"text": "",
"color": "gray"
},
+ "color": "#2134B0",
+ "notes": "",
"options": {
"edge": "undefined"
- },
- "color": "#2134B0",
- "notes": ""
+ }
},
{
"id": "1699964678894",
@@ -1716,11 +1714,11 @@
"text": "modbus_to_dido",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "modbus_to_dido"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1699964793925",
@@ -1740,13 +1738,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1699965957410",
@@ -1795,9 +1793,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#2134B0",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1700411878636",
@@ -1846,9 +1844,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#5CB36D",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1714752862828",
@@ -1866,13 +1864,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1717441414646",
@@ -1901,13 +1899,13 @@
"text": "",
"color": "gray"
},
+ "color": "#656D78",
+ "notes": "",
"options": {
"keepmessage": true,
"code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n\telse if(value.status === \"NOK-thermometer\")\n\t{\n\t\tsend(0, {\"thermometer\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"temperature\"))\n\t{\n\t\tsend(0, {\"thermometer\": \"OK\"});\n\t}\n}",
"outputs": 1
- },
- "color": "#656D78",
- "notes": ""
+ }
},
{
"id": "1717442627834",
@@ -1927,13 +1925,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1717442631338",
@@ -1951,11 +1949,11 @@
"text": "send-to-services",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1718016045116",
@@ -1980,11 +1978,11 @@
"text": "tb-push",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1718016052341",
@@ -2013,15 +2011,15 @@
"text": "Running",
"color": "gray"
},
+ "color": "#30E193",
+ "notes": "",
"options": {
"slack_channel": "C071KN2Q8SK",
"tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]",
"message_includes": "[\"is responding again\", \"Flow has been restarted\", \"Node db has changed\"]",
"types": "[\"emergency\", \"critical\", \"error\", \"alert\"]",
- "name": "rvo_senica_33_10.0.0.127"
- },
- "color": "#30E193",
- "notes": ""
+ "name": "test_rvo_debian12"
+ }
},
{
"id": "1718016073501",
@@ -2046,13 +2044,13 @@
"text": "",
"color": "gray"
},
- "options": {
- "stringify": "json",
- "method": "POST",
- "url": "http://192.168.252.2:8004/slack"
- },
"color": "#5D9CEC",
- "notes": ""
+ "notes": "",
+ "options": {
+ "url": "http://192.168.252.2:8004/slack",
+ "method": "POST",
+ "stringify": "json"
+ }
},
{
"id": "1718016086212",
@@ -2072,13 +2070,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1718016094070",
@@ -2103,12 +2101,12 @@
"text": "",
"color": "gray"
},
- "options": {
- "datatype": "object",
- "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }"
- },
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {
+ "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }",
+ "datatype": "object"
+ }
},
{
"id": "1729855334955",
@@ -2126,11 +2124,11 @@
"text": "platform-rpc-call",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "platform-rpc-call"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1729855371093",
@@ -2148,13 +2146,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1731068658334",
@@ -2179,11 +2177,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731068754606",
@@ -2212,15 +2210,15 @@
"text": "Connected",
"color": "green"
},
+ "color": "#888600",
+ "notes": "",
"options": {
"username": "",
"clientid": "",
"port": "2764",
"host": "192.168.252.2",
- "topic": ""
- },
- "color": "#888600",
- "notes": ""
+ "topic": "u38"
+ }
},
{
"id": "1731069001548",
@@ -2251,9 +2249,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#888600",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069033416",
@@ -2271,11 +2269,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731069059135",
@@ -2300,9 +2298,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#888600",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069079243",
@@ -2320,13 +2318,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1731069116691",
@@ -2351,9 +2349,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069131637",
@@ -2378,9 +2376,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069137374",
@@ -2405,9 +2403,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069179846",
@@ -2432,9 +2430,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069192937",
@@ -2459,9 +2457,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731069264443",
@@ -2486,11 +2484,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731069334626",
@@ -2515,11 +2513,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731069548145",
@@ -2544,11 +2542,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731069567152",
@@ -2573,11 +2571,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731070156936",
@@ -2602,11 +2600,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1731234189516",
@@ -2631,9 +2629,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1731234189551",
@@ -2658,9 +2656,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1732700042559",
@@ -2689,9 +2687,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#888600",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1732700057052",
@@ -2716,11 +2714,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1732700071298",
@@ -2738,13 +2736,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1732700642917",
@@ -2762,11 +2760,11 @@
"text": "tb-push",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1732889185927",
@@ -2784,13 +2782,13 @@
"text": "Enabled",
"color": "gray"
},
+ "color": "#967ADC",
+ "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- },
- "color": "#967ADC",
- "notes": ""
+ }
},
{
"id": "1733574412965",
@@ -2815,11 +2813,11 @@
"text": "db-init",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "db-init"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1747561603739",
@@ -2837,11 +2835,11 @@
"text": "send-to-services",
"color": "gray"
},
+ "color": "#303E4D",
+ "notes": "",
"options": {
"wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
+ }
},
{
"id": "1747562867845",
@@ -2859,9 +2857,9 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#704cff",
- "notes": ""
+ "notes": "",
+ "options": {}
},
{
"id": "1749211698385",
@@ -2886,10 +2884,10 @@
"text": "",
"color": "gray"
},
- "options": {},
"color": "#F6BB42",
- "notes": ""
+ "notes": "",
+ "options": {}
}
],
- "version": 615
-}
+ "version": 624
+}
\ No newline at end of file
diff --git a/flow/designer.json_orig b/flow/designer.json_orig
new file mode 100644
index 0000000..eb18e86
--- /dev/null
+++ b/flow/designer.json_orig
@@ -0,0 +1,2775 @@
+{
+ "tabs": [
+ {
+ "name": "MAIN PUSH",
+ "linker": "main-push",
+ "id": "1612772287426",
+ "index": 0
+ },
+ {
+ "name": "CMD manager",
+ "linker": "cmd-manager",
+ "id": "1615551125555",
+ "index": 1
+ },
+ {
+ "name": "Devices",
+ "linker": "devices",
+ "id": "1611921777196",
+ "index": 2
+ }
+ ],
+ "components": [
+ {
+ "id": "1611951142547",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "ERROR",
+ "x": 598,
+ "y": 60,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#DA4453",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1612776786008",
+ "component": "wsmqttpublish",
+ "tab": "1612772287426",
+ "name": "WS MQTT publish",
+ "x": 290.75,
+ "y": 189,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1615551060773"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1618300858252"
+ },
+ {
+ "index": "0",
+ "id": "1618558465485"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1634303685503"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Connected",
+ "color": "green"
+ },
+ "color": "#888600",
+ "notes": "",
+ "options": {
+ "username": "",
+ "clientid": "",
+ "port": "1883",
+ "host": ""
+ }
+ },
+ {
+ "id": "1612778461252",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "tb-push",
+ "x": 72.75,
+ "y": 328,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1612783322136"
+ },
+ {
+ "index": "1",
+ "id": "1612776786008"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "tb-push"
+ }
+ },
+ {
+ "id": "1612783322136",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "to TB",
+ "x": 290.75,
+ "y": 330,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1615551060773",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "errors from MQTT Broker",
+ "x": 594,
+ "y": 57,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#DA4453",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1615563373927",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "Debug",
+ "x": 755,
+ "y": 155,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#DA4453",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1615566865233",
+ "component": "virtualwireout",
+ "tab": "1615551125555",
+ "name": "tb-push",
+ "x": 755,
+ "y": 248,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "tb-push"
+ }
+ },
+ {
+ "id": "1615798582262",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "CMD_debug",
+ "x": 755,
+ "y": 346,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1615802995322",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "Debug",
+ "x": 596.8833312988281,
+ "y": 566.3500061035156,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Disabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": false
+ }
+ },
+ {
+ "id": "1615809128443",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "tempToTb",
+ "x": 595.8833312988281,
+ "y": 658.3500061035156,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1615809595184",
+ "component": "virtualwireout",
+ "tab": "1611921777196",
+ "name": "tb-push",
+ "x": 597.8833312988281,
+ "y": 377.25,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "tb-push"
+ }
+ },
+ {
+ "id": "1616165795916",
+ "component": "httproute",
+ "tab": "1615551125555",
+ "name": "POST /terminal",
+ "x": 135,
+ "y": 547,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1684060205000"
+ },
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Listening",
+ "color": "green"
+ },
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false,
+ "options": {
+ "timeout": 10,
+ "cachepolicy": 0,
+ "cacheexpire": "5 minutes",
+ "size": 5,
+ "url": "/terminal",
+ "method": "POST",
+ "name": "",
+ "flags": [
+ 10000,
+ "id:1616165795916",
+ "post"
+ ],
+ "emptyresponse": false
+ }
+ },
+ {
+ "id": "1616165824813",
+ "component": "httpresponse",
+ "tab": "1615551125555",
+ "name": "HTTP Response",
+ "x": 753,
+ "y": 423,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#5D9CEC",
+ "notes": "",
+ "options": {
+ "datatype": "json"
+ }
+ },
+ {
+ "id": "1617104731852",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "DIDO_Debug",
+ "x": 669,
+ "y": 1040,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1617114651703",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "turnOff line",
+ "x": 133,
+ "y": 1161,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1699963668903"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "data": "{line: 1, command: \"off\", force: true}",
+ "datatype": "object"
+ }
+ },
+ {
+ "id": "1617115013095",
+ "component": "virtualwireout",
+ "tab": "1615551125555",
+ "name": "tb-push",
+ "x": 669,
+ "y": 1150,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "tb-push"
+ }
+ },
+ {
+ "id": "1617284749681",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "update profile / node",
+ "x": 112,
+ "y": 208,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "datatype": "string",
+ "data": "profile_nodes"
+ }
+ },
+ {
+ "id": "1618235171399",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "tun tasks",
+ "x": 184,
+ "y": 279,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "data": "run"
+ }
+ },
+ {
+ "id": "1618300858252",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "wsmqtt-exit1",
+ "x": 597.8833312988281,
+ "y": 149,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1618393583970",
+ "component": "virtualwireout",
+ "tab": "1615551125555",
+ "name": "to-cmd-manager",
+ "x": 668.8833312988281,
+ "y": 1269,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "from-dido-controller",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "from-dido-controller"
+ }
+ },
+ {
+ "id": "1618393674428",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "platform-rpc-call",
+ "x": 132.88333129882812,
+ "y": 367,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "platform-rpc-call",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "platform-rpc-call"
+ }
+ },
+ {
+ "id": "1618393759854",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "cmd_to_dido",
+ "x": 119.88333129882812,
+ "y": 1007,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1683664161036"
+ },
+ {
+ "index": "1",
+ "id": "1699963668903"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "cmd_to_dido",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "cmd_to_dido"
+ }
+ },
+ {
+ "id": "1618393827655",
+ "component": "virtualwireout",
+ "tab": "1615551125555",
+ "name": "cmd_to_dido",
+ "x": 752.8833312988281,
+ "y": 527,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "cmd_to_dido",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "cmd_to_dido"
+ }
+ },
+ {
+ "id": "1618558465485",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "platform-rpc-call",
+ "x": 597.8833312988281,
+ "y": 247,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "platform-rpc-call",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "platform-rpc-call"
+ }
+ },
+ {
+ "id": "1618572059773",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "turnOn line",
+ "x": 132,
+ "y": 1085,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1699963668903"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "datatype": "object",
+ "data": "{line: 1, command: \"on\", force: true}"
+ }
+ },
+ {
+ "id": "1619515097737",
+ "component": "cmd_manager",
+ "tab": "1615551125555",
+ "name": "CMD Manager",
+ "x": 452.1091003417969,
+ "y": 341.05455017089844,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1615563373927"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1615566865233"
+ },
+ {
+ "index": "0",
+ "id": "1615798582262"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1616165824813"
+ }
+ ],
+ "3": [
+ {
+ "index": "0",
+ "id": "1618393827655"
+ }
+ ],
+ "4": [
+ {
+ "index": "0",
+ "id": "1635936391935"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#5D9CEC",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1619605019281",
+ "component": "httproute",
+ "tab": "1615551125555",
+ "name": "GET db",
+ "x": 173,
+ "y": 653,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1684060205000"
+ },
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Listening",
+ "color": "green"
+ },
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false,
+ "options": {
+ "timeout": 5,
+ "cachepolicy": 0,
+ "cacheexpire": "5 minutes",
+ "size": 5,
+ "url": "/db",
+ "method": "GET",
+ "name": "",
+ "flags": [
+ 5000,
+ "id:1619605019281",
+ "get"
+ ]
+ }
+ },
+ {
+ "id": "1619784672383",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "turnOnAlarm",
+ "x": 117,
+ "y": 1242,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1699963668903"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "data": "{command: \"turnOnAlarm\"}",
+ "datatype": "object"
+ }
+ },
+ {
+ "id": "1619784812964",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "turnOffAlarm",
+ "x": 118,
+ "y": 1307,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1699963668903"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "data": "{command: \"turnOffAlarm\"}",
+ "datatype": "object"
+ }
+ },
+ {
+ "id": "1621340721628",
+ "component": "virtualwireout",
+ "tab": "1611921777196",
+ "name": "modbus_to_dido",
+ "x": 599,
+ "y": 471,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "modbus_to_dido",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "modbus_to_dido"
+ }
+ },
+ {
+ "id": "1622640022885",
+ "component": "httproute",
+ "tab": "1615551125555",
+ "name": "POST /db_connector",
+ "x": 98,
+ "y": 1586,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1622640073521"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Listening",
+ "color": "green"
+ },
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false,
+ "options": {
+ "timeout": 5,
+ "cachepolicy": 0,
+ "cacheexpire": "5 minutes",
+ "size": 5,
+ "url": "/db_connector",
+ "method": "POST",
+ "flags": [
+ 5000,
+ "id:1622640022885",
+ "post"
+ ]
+ }
+ },
+ {
+ "id": "1622640073521",
+ "component": "db_connector",
+ "tab": "1615551125555",
+ "name": "DbConnector",
+ "x": 372,
+ "y": 1572,
+ "connections": {
+ "1": [
+ {
+ "index": "0",
+ "id": "1622641420685"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#2134B0",
+ "notes": "",
+ "options": {
+ "edge": "undefined"
+ }
+ },
+ {
+ "id": "1622641420685",
+ "component": "httpresponse",
+ "tab": "1615551125555",
+ "name": "HTTP Response",
+ "x": 596,
+ "y": 1586,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#5D9CEC",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1634303504177",
+ "component": "monitormemory",
+ "tab": "1612772287426",
+ "name": "RAM",
+ "x": 69.88333129882812,
+ "y": 888.5,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634465281992"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "704.30 MB / 982.12 MB",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "enabled": true,
+ "interval": 30000
+ }
+ },
+ {
+ "id": "1634303533779",
+ "component": "monitordisk",
+ "tab": "1612772287426",
+ "name": "disk",
+ "x": 70.88333129882812,
+ "y": 982.5,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634465821120"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "5.45 GB / 6.86 GB",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "enabled": true,
+ "path": "/",
+ "interval": 30000
+ }
+ },
+ {
+ "id": "1634303595494",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "send-to-services",
+ "x": 51.883331298828125,
+ "y": 1400.5,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634463186563"
+ },
+ {
+ "index": "1",
+ "id": "1634488120710"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "send-to-services",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "send-to-services"
+ }
+ },
+ {
+ "id": "1634303602169",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "send-to-services",
+ "x": 426.8833312988281,
+ "y": 878.5,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "send-to-services",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "send-to-services"
+ }
+ },
+ {
+ "id": "1634303685503",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "send-to-services",
+ "x": 600.8833312988281,
+ "y": 341.5,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "send-to-services",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "send-to-services"
+ }
+ },
+ {
+ "id": "1634303743260",
+ "component": "httprequest",
+ "tab": "1612772287426",
+ "name": "192.168.252.2:8004/sentmessage",
+ "reference": "",
+ "x": 506.8833312988281,
+ "y": 1331.7333374023438,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1635327431236"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#5D9CEC",
+ "notes": "",
+ "options": {
+ "stringify": "json",
+ "method": "POST",
+ "url": "http://192.168.252.2:8004/sentmessage"
+ }
+ },
+ {
+ "id": "1634463186563",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Debug",
+ "x": 305.75,
+ "y": 1442,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1634464580289",
+ "component": "code",
+ "tab": "1612772287426",
+ "name": "Code",
+ "x": 245,
+ "y": 787,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634465243324"
+ },
+ {
+ "index": "0",
+ "id": "1634303602169"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#656D78",
+ "notes": "",
+ "options": {
+ "keepmessage": true,
+ "code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);",
+ "outputs": 1
+ }
+ },
+ {
+ "id": "1634465243324",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Debug",
+ "x": 428,
+ "y": 784,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1634465281992",
+ "component": "code",
+ "tab": "1612772287426",
+ "name": "Code",
+ "x": 245,
+ "y": 884,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634465338103"
+ },
+ {
+ "index": "0",
+ "id": "1634303602169"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#656D78",
+ "notes": "",
+ "options": {
+ "keepmessage": true,
+ "code": "value.sender = \"ram\";\n\nlet response = {};\n\nresponse.memory_total = Math.round(value.total / (1024 ** 2));\nresponse.memory_free = Math.round(value.free / (1024 ** 2));\nresponse.memory_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
+ "outputs": 1
+ }
+ },
+ {
+ "id": "1634465338103",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Debug",
+ "x": 429,
+ "y": 976,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1634465821120",
+ "component": "code",
+ "tab": "1612772287426",
+ "name": "Code",
+ "x": 245,
+ "y": 978,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634465892500"
+ },
+ {
+ "index": "0",
+ "id": "1634303602169"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#656D78",
+ "notes": "",
+ "options": {
+ "keepmessage": true,
+ "code": "value.sender = \"hdd\";\n\nlet response = {};\n\nresponse.hdd_total = Math.round(value.total / (1024 ** 2));\nresponse.hdd_free = Math.round(value.free / (1024 ** 2));\nresponse.hdd_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
+ "outputs": 1
+ }
+ },
+ {
+ "id": "1634465892500",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Debug",
+ "x": 432,
+ "y": 1068,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1634484067516",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Send info",
+ "x": 513,
+ "y": 1441,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1634488120710",
+ "component": "infosender",
+ "tab": "1612772287426",
+ "name": "Info sender",
+ "x": 301,
+ "y": 1336,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634484067516"
+ },
+ {
+ "index": "0",
+ "id": "1634303743260"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#2134B0",
+ "notes": "",
+ "options": {
+ "edge": "undefined"
+ }
+ },
+ {
+ "id": "1635327431236",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Debug",
+ "x": 837.8833312988281,
+ "y": 1325.5,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1635936391935",
+ "component": "virtualwireout",
+ "tab": "1615551125555",
+ "name": "send-to-services",
+ "x": 753,
+ "y": 623,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "send-to-services",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "send-to-services"
+ }
+ },
+ {
+ "id": "1637069803394",
+ "component": "monitorconsumption",
+ "tab": "1612772287426",
+ "name": "CPU",
+ "x": 69,
+ "y": 791,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634464580289"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "3.6% / 111.50 MB",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "monitorfiles": true,
+ "monitorconnections": true,
+ "monitorsize": true,
+ "monitorconsumption": true,
+ "enabled": true,
+ "interval": 30000
+ }
+ },
+ {
+ "id": "1683664161036",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "CMDtoDIDO",
+ "x": 392,
+ "y": 1012,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1683981346282",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "from-dido-controller",
+ "x": 112,
+ "y": 459,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1684055037116"
+ },
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "from-dido-controller",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "from-dido-controller"
+ }
+ },
+ {
+ "id": "1684055037116",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "from dido to cmd",
+ "x": 451,
+ "y": 532,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1684060205000",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "HTTP routes",
+ "x": 450,
+ "y": 639,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1684179110403",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "MDBToDido",
+ "x": 598,
+ "y": 147,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1699963668903",
+ "component": "dido_controller",
+ "tab": "1615551125555",
+ "name": "DIDO_Controller",
+ "x": 397,
+ "y": 1131,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1617104731852"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1617104731852"
+ },
+ {
+ "index": "0",
+ "id": "1617115013095"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1618393583970"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#2134B0",
+ "notes": "",
+ "options": {
+ "edge": "undefined"
+ }
+ },
+ {
+ "id": "1699964678894",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "modbus_to_dido",
+ "x": 96,
+ "y": 924,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1699963668903"
+ },
+ {
+ "index": "0",
+ "id": "1699964793925"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "modbus_to_dido",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "modbus_to_dido"
+ }
+ },
+ {
+ "id": "1699964793925",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "modbusToDido",
+ "x": 388,
+ "y": 920,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1699965957410",
+ "component": "modbus_reader",
+ "tab": "1611921777196",
+ "name": "Modbus reader",
+ "x": 232,
+ "y": 175,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1611951142547"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1621340721628"
+ },
+ {
+ "index": "0",
+ "id": "1684179110403"
+ },
+ {
+ "index": "0",
+ "id": "1717441414646"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1615809595184"
+ },
+ {
+ "index": "0",
+ "id": "1714752862828"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#2134B0",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1700411878636",
+ "component": "thermometer",
+ "tab": "1611921777196",
+ "name": "Thermometer",
+ "x": 234.75,
+ "y": 444,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1615802995322"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1615809595184"
+ },
+ {
+ "index": "0",
+ "id": "1615809128443"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1621340721628"
+ },
+ {
+ "index": "0",
+ "id": "1732889185927"
+ },
+ {
+ "index": "0",
+ "id": "1717441414646"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#5CB36D",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1714752862828",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "MDBToTb",
+ "x": 766,
+ "y": 324,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1717441414646",
+ "component": "code",
+ "tab": "1611921777196",
+ "name": "device-status",
+ "x": 764.0833282470703,
+ "y": 222,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1717442627834"
+ },
+ {
+ "index": "0",
+ "id": "1717442631338"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#656D78",
+ "notes": "",
+ "options": {
+ "keepmessage": true,
+ "code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n\telse if(value.status === \"NOK-thermometer\")\n\t{\n\t\tsend(0, {\"thermometer\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"temperature\"))\n\t{\n\t\tsend(0, {\"thermometer\": \"OK\"});\n\t}\n}",
+ "outputs": 1
+ }
+ },
+ {
+ "id": "1717442627834",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "modbus service",
+ "x": 966.0833282470703,
+ "y": 165,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1717442631338",
+ "component": "virtualwireout",
+ "tab": "1611921777196",
+ "name": "send-to-services",
+ "x": 968.0833282470703,
+ "y": 268,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "send-to-services",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "send-to-services"
+ }
+ },
+ {
+ "id": "1718016045116",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "tb-push",
+ "x": 77.75,
+ "y": 1630,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1718016052341"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "tb-push"
+ }
+ },
+ {
+ "id": "1718016052341",
+ "component": "slack_filter",
+ "tab": "1612772287426",
+ "name": "Slack Filter",
+ "x": 296,
+ "y": 1671,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1718016086212"
+ },
+ {
+ "index": "0",
+ "id": "1718016073501"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Running",
+ "color": "gray"
+ },
+ "color": "#30E193",
+ "notes": "",
+ "options": {
+ "slack_channel": "C071KN2Q8SK",
+ "tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]",
+ "message_includes": "[\"is responding again\", \"Flow has been restarted\", \"Node db has changed\"]",
+ "types": "[\"emergency\", \"critical\", \"error\", \"alert\"]",
+ "name": "test_rvo_debian12"
+ }
+ },
+ {
+ "id": "1718016073501",
+ "component": "httprequest",
+ "tab": "1612772287426",
+ "name": "http://192.168.252.2:8004/slack",
+ "x": 495,
+ "y": 1753,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1718016086212"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#5D9CEC",
+ "notes": "",
+ "options": {
+ "stringify": "json",
+ "method": "POST",
+ "url": "http://192.168.252.2:8004/slack"
+ }
+ },
+ {
+ "id": "1718016086212",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "Debug",
+ "x": 832,
+ "y": 1664,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1718016094070",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "Trigger",
+ "x": 79,
+ "y": 1723,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1718016052341"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {
+ "datatype": "object",
+ "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }"
+ }
+ },
+ {
+ "id": "1731068658334",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 79.75,
+ "y": 164,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1612776786008"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731069001548",
+ "component": "db_init",
+ "tab": "1612772287426",
+ "name": "DB Initialization",
+ "x": 1003.75,
+ "y": 240.25,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1731069033416"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1747561603739"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#888600",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069033416",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 1244.75,
+ "y": 233.25,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731069059135",
+ "component": "showdb",
+ "tab": "1612772287426",
+ "name": "Show db data",
+ "x": 1121.75,
+ "y": 814.25,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1731069079243"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#888600",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069079243",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "dbData",
+ "x": 1324.75,
+ "y": 863.25,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1731069116691",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "settings",
+ "x": 867.75,
+ "y": 667.75,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069131637",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "relaysData",
+ "x": 798.75,
+ "y": 733.75,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069137374",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "nodesData",
+ "x": 762.75,
+ "y": 801.75,
+ "connections": {
+ "0": [
+ {
+ "index": "2",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069179846",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "pinsData",
+ "x": 782.75,
+ "y": 867.75,
+ "connections": {
+ "0": [
+ {
+ "index": "3",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069192937",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "sample data",
+ "x": 801.75,
+ "y": 933.75,
+ "connections": {
+ "0": [
+ {
+ "index": "4",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731069264443",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 63.75,
+ "y": 1279,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1634488120710"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731069334626",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "db-init",
+ "x": 172.88333129882812,
+ "y": 129,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731069548145",
+ "component": "virtualwirein",
+ "tab": "1611921777196",
+ "name": "db-init",
+ "x": 46.75,
+ "y": 192,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1699965957410"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731069567152",
+ "component": "virtualwirein",
+ "tab": "1611921777196",
+ "name": "db-init",
+ "x": 44.75,
+ "y": 465,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1700411878636"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731070156936",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "db-init",
+ "x": 126.88333129882812,
+ "y": 1377,
+ "connections": {
+ "0": [
+ {
+ "index": "2",
+ "id": "1699963668903"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1731234189516",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "monitor.txt",
+ "x": 821.75,
+ "y": 1000.75,
+ "connections": {
+ "0": [
+ {
+ "index": "5",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1731234189551",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "err.txt",
+ "x": 862.75,
+ "y": 1064.75,
+ "connections": {
+ "0": [
+ {
+ "index": "6",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1732700042559",
+ "component": "nodesdb_change_check",
+ "tab": "1612772287426",
+ "name": "Nodes DB change check",
+ "x": 263.8833312988281,
+ "y": 1993.2333984375,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1732700071298"
+ },
+ {
+ "index": "0",
+ "id": "1732700642917"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#888600",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1732700057052",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 84.75,
+ "y": 1994,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1732700042559"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "db-init"
+ }
+ },
+ {
+ "id": "1732700071298",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "nodesChange",
+ "x": 561.8833312988281,
+ "y": 2055.2333984375,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1732700642917",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "tb-push",
+ "x": 557.8833312988281,
+ "y": 1949,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "tb-push"
+ }
+ },
+ {
+ "id": "1732889185927",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "tempToDido",
+ "x": 594.8833312988281,
+ "y": 753,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "color": "#967ADC",
+ "notes": "",
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ }
+ },
+ {
+ "id": "1747561603739",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "send-to-services",
+ "x": 1243.8833312988281,
+ "y": 334.5,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "send-to-services",
+ "color": "gray"
+ },
+ "color": "#303E4D",
+ "notes": "",
+ "options": {
+ "wirename": "send-to-services"
+ }
+ },
+ {
+ "id": "1747562867845",
+ "component": "comment",
+ "tab": "1612772287426",
+ "name": "FLOW STARTING POINT",
+ "x": 1003.5666656494141,
+ "y": 178,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#704cff",
+ "notes": "",
+ "options": {}
+ },
+ {
+ "id": "1750771612786",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "devices",
+ "x": 896.75,
+ "y": 1122.75,
+ "connections": {
+ "0": [
+ {
+ "index": "7",
+ "id": "1731069059135"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "color": "#F6BB42",
+ "notes": "",
+ "options": {}
+ }
+ ],
+ "version": 624
+}
\ No newline at end of file
diff --git a/flow/dido_controller.js b/flow/dido_controller.js
index d16fb19..8843fe0 100644
--- a/flow/dido_controller.js
+++ b/flow/dido_controller.js
@@ -364,7 +364,7 @@ exports.install = function(instance) {
data.map(item => {
let value = item['value'];
- let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01"
+ let pin = item["dev"] + item["circuit"]; // for example "ro1_03" or "di1_01"
if (pin == undefined) return;
switchLogic(pin, value);
@@ -516,9 +516,9 @@ exports.install = function(instance) {
}
else if (ws) {
- //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
+ //pin = "ro1_03" or "di1_01" ... we must make just "1_01" with slice method
monitor.info(`Dido: turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
- let cmd = { "cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": value };
+ let cmd = { "cmd": "set", "dev": "relay", "circuit": pin.slice(2), "value": value };
ws.send(JSON.stringify(cmd));
}
@@ -754,9 +754,9 @@ exports.install = function(instance) {
pins = [4, 6];
}
} else if (controllerType === "unipi") {
- pins = ["input1_01", "input1_04", "input1_05"];
+ pins = ["di1_01", "di1_04", "di1_05"];
if (hasMainSwitch === 1) {
- pins = ["input1_01", "input1_04"];
+ pins = ["di1_01", "di1_04"];
}
}
@@ -781,7 +781,7 @@ exports.install = function(instance) {
for (const pinIndex of pinIndexes) {
if (previousValues[pinIndex] === 0) {
- if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && SETTINGS.maintenance_mode) continue;
+ if ((pinIndex === 6 || pinIndex === 'di1_01' || pinIndex === 'di1_05') && SETTINGS.maintenance_mode) continue;
status = "NOK";
break;
}
@@ -798,7 +798,7 @@ exports.install = function(instance) {
// we pass array to function in case of rsPort ==> switchLogic([55,3,0,1]) ==> [[55,3,0,1]]
- // we pass two values in case of websocket ==> switchLogic("relay1_03",1) ==> ["relay1_03",1]
+ // we pass two values in case of websocket ==> switchLogic("ro1_03",1) ==> ["ro1_03",1]
const switchLogic = (...args) => {
let values = {};
@@ -849,18 +849,18 @@ exports.install = function(instance) {
else if (type == "rotary_switch_state") {
// combination of these two pins required to get result
let pin2, pin3;
- if (pinIndex == 2 || pinIndex == "input1_02") {
+ if (pinIndex == 2 || pinIndex == "di1_02") {
pin2 = newPinValue;
- pin3 = previousValues[3] || previousValues["input1_03"];
+ pin3 = previousValues[3] || previousValues["di1_03"];
if (pin3 == undefined) {
previousValues[pinIndex] = newPinValue;
return;
}
}
- else if (pinIndex == 3 || pinIndex == "input1_03") {
+ else if (pinIndex == 3 || pinIndex == "di1_03") {
pin3 = newPinValue;
- pin2 = previousValues[2] || previousValues["input1_02"];
+ pin2 = previousValues[2] || previousValues["di1_02"];
if (pin2 == undefined) {
previousValues[pinIndex] = newPinValue;
@@ -913,7 +913,7 @@ exports.install = function(instance) {
}
//Dverovy kontakt - pin 6
- //! Ak je rvo s dvoma dverovymi kontaktami, ked pride z evoku signal z input1_05, co bol predytm "state_of_main switch" handlujeme ho teraz ako 'door_condition'
+ //! Ak je rvo s dvoma dverovymi kontaktami, ked pride z evoku signal z di1_05, co bol predytm "state_of_main switch" handlujeme ho teraz ako 'door_condition'
else if (type == "door_condition" || type === "state_of_main_switch") {
newPinValue === 0 ? value = "open" : value = "closed";
@@ -1369,60 +1369,60 @@ exports.install = function(instance) {
//! pins.table --> from UNIPI
// pin:string|type:string|line:number
-// *|input1_01|state_of_main_switch|0|...........
-// *|input1_02|rotary_switch_state|0|...........
-// *|input1_03|rotary_switch_state|0|...........
+// *|di1_01|state_of_main_switch|0|...........
+// *|di1_02|rotary_switch_state|0|...........
+// *|di1_03|rotary_switch_state|0|...........
// *|intut1_04|power_supply|0|...........
-// *|input1_05|door_condition|0|...........
-// *|input1_06|state_of_breaker|1|...........
-// *|input1_07|state_of_breaker|2|...........
-// *|input1_08|state_of_breaker|3|...........
-// *|relay1_02|state_of_contactor|1|...........
-// *|relay1_03|state_of_contactor|2|...........
-// *|relay1_04|state_of_contactor|3|...........
+// *|di1_05|door_condition|0|...........
+// *|di1_06|state_of_breaker|1|...........
+// *|di1_07|state_of_breaker|2|...........
+// *|di1_08|state_of_breaker|3|...........
+// *|ro1_02|state_of_contactor|1|...........
+// *|ro1_03|state_of_contactor|2|...........
+// *|ro1_04|state_of_contactor|3|...........
// *|287D8776E0013CE9|temperature|0|...........
//! pins_data --> from UNIPI
// {
-// input1_01: {
-// pin: 'input1_01',
+// di1_01: {
+// pin: 'di1_01',
// type: 'door_condition',
// line: 0,
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
// },
-// input1_02: {
-// pin: 'input1_02',
+// di1_02: {
+// pin: 'di1_02',
// type: 'rotary_switch_state',
// line: 0,
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
// },
-// input1_03: {
-// pin: 'input1_03',
+// di1_03: {
+// pin: 'di1_03',
// type: 'rotary_switch_state',
// line: 0,
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
// },
-// input1_04: {
-// pin: 'input1_04',
+// di1_04: {
+// pin: 'di1_04',
// type: 'power_supply',
// line: 0,
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
// },
-// input1_05: {
-// pin: 'input1_05',
+// di1_05: {
+// pin: 'di1_05',
// type: 'state_of_main_switch',
// line: 0,
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
// },
-// input1_06: {
-// pin: 'input1_06',
+// di1_06: {
+// pin: 'di1_06',
// type: 'state_of_breaker',
// line: 1,
// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
// },
-// relay1_02: {
-// pin: 'relay1_02',
+// ro1_02: {
+// pin: 'ro1_02',
// type: 'state_of_contactor',
// line: 1,
// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
diff --git a/flow/helper/DataToTbHandler.js b/flow/helper/DataToTbHandler.js
index 716ef7b..ef6942a 100644
--- a/flow/helper/DataToTbHandler.js
+++ b/flow/helper/DataToTbHandler.js
@@ -1,186 +1,186 @@
class DataToTbHandler {
- constructor(index) {
- this.index = index;
+ constructor(index) {
+ this.index = index;
- // time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
- this.timeToHoldTbValue = 30 * 60; //30 minutes
- this.previousValues = {};
- this.debug = false;
- this.messageCounter = 0;
- this.itIsNodeReadout = false;
- this.sender = "";
+ // time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
+ this.timeToHoldTbValue = 30 * 60; //30 minutes
+ this.previousValues = {};
+ this.debug = false;
+ this.messageCounter = 0;
+ this.itIsNodeReadout = false;
+ this.sender = "";
- // if attribute change difference is less than limit value, we do not send to tb.
- this.attributeChangeLimit = {
- temperature: 0.5,
- Phase_1_voltage: 2,
- Phase_2_voltage: 2,
- Phase_3_voltage: 2,
- Phase_1_current: 0.1,
- Phase_2_current: 0.1,
- Phase_3_current: 0.1,
- Phase_1_power: 2,
- Phase_2_power: 2,
- Phase_3_power: 2,
- total_power: 2,
- total_energy: 1,
- Phase_1_pow_factor: 0.1,
- Phase_2_pow_factor: 0.1,
- Phase_3_pow_factor: 0.1,
- power_factor: 0.1,
- lifetime: 2,
- voltage: 2,
- power: 2,
- frequency: 3,
- energy: 0.1,
- current: 2,
- inclination_x: 10,
- inclination_y: 10,
- inclination_z: 10
- };
+ // if attribute change difference is less than limit value, we do not send to tb.
+ this.attributeChangeLimit = {
+ temperature: 0.5,
+ Phase_1_voltage: 2,
+ Phase_2_voltage: 2,
+ Phase_3_voltage: 2,
+ Phase_1_current: 0.1,
+ Phase_2_current: 0.1,
+ Phase_3_current: 0.1,
+ Phase_1_power: 2,
+ Phase_2_power: 2,
+ Phase_3_power: 2,
+ total_power: 2,
+ total_energy: 1,
+ Phase_1_pow_factor: 0.1,
+ Phase_2_pow_factor: 0.1,
+ Phase_3_pow_factor: 0.1,
+ power_factor: 0.1,
+ lifetime: 2,
+ voltage: 2,
+ power: 2,
+ frequency: 3,
+ energy: 0.1,
+ current: 2,
+ inclination_x: 10,
+ inclination_y: 10,
+ inclination_z: 10
+ };
- }
+ }
- dump() {
- console.log("----------------------------");
- console.log("previousValues", this.previousValues);
- console.log("----------------------------");
- }
+ dump() {
+ console.log("----------------------------");
+ console.log("previousValues", this.previousValues);
+ console.log("----------------------------");
+ }
- setSender(sender) {
- this.sender = sender;
- }
+ setSender(sender) {
+ this.sender = sender;
+ }
- isEmptyObject(obj) {
- for (var _ in obj) {
- return false;
- }
- return true;
- }
+ isEmptyObject(obj) {
+ for (var _ in obj) {
+ return false;
+ }
+ return true;
+ }
- sendToTb(data, instance) {
+ sendToTb(data, instance) {
- //not to modify data object, we do deep copy:
- let dataCopy = JSON.parse(JSON.stringify(data));
+ //not to modify data object, we do deep copy:
+ let dataCopy = JSON.parse(JSON.stringify(data));
- let keys = Object.keys(dataCopy);
+ let keys = Object.keys(dataCopy);
- if (keys.length == 0) {
- if (this.debug) console.log("sendToTb received empty object", dataCopy);
- return;
- }
+ if (keys.length == 0) {
+ if (this.debug) console.log("sendToTb received empty object", dataCopy);
+ return;
+ }
- let tbname = keys[0];
- let ts;
+ let tbname = keys[0];
+ let ts;
- let arrayOfValues = dataCopy[tbname];
- let arrayOfValuesToSend = [];
+ let arrayOfValues = dataCopy[tbname];
+ let arrayOfValuesToSend = [];
- for (let i = 0; i < arrayOfValues.length; i++) {
+ for (let i = 0; i < arrayOfValues.length; i++) {
- ts = arrayOfValues[i].ts;
- let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
+ ts = arrayOfValues[i].ts;
+ let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
- if (!this.isEmptyObject(values)) {
- arrayOfValuesToSend.push({ ts: ts, values: values });
- }
+ if (!this.isEmptyObject(values)) {
+ arrayOfValuesToSend.push({ ts: ts, values: values });
+ }
- }
+ }
- if (arrayOfValuesToSend.length == 0) {
- //if(this.debug) console.log("data not sent - empty array");
- return;
- }
+ if (arrayOfValuesToSend.length == 0) {
+ //if(this.debug) console.log("data not sent - empty array");
+ return;
+ }
- this.messageCounter++;
+ this.messageCounter++;
- let dataToTbModified = {
- [tbname]: arrayOfValuesToSend
- }
+ let dataToTbModified = {
+ [tbname]: arrayOfValuesToSend
+ }
- //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
- //if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
- instance.send(this.index, dataToTbModified);
- }
+ //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
+ //if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
+ instance.send(this.index, dataToTbModified);
+ }
- getDiffTimestamp(key) {
- //TODO set different value for given key!!!
- //if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
- return this.timeToHoldTbValue * 1000;
- }
+ getDiffTimestamp(key) {
+ //TODO set different value for given key!!!
+ //if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
+ return this.timeToHoldTbValue * 1000;
+ }
- prepareValuesForTb(tbname, timestamp, values) {
+ prepareValuesForTb(tbname, timestamp, values) {
- let keys = Object.keys(values);
+ let keys = Object.keys(values);
- if (keys.includes("lifetime")) this.itIsNodeReadout = true;
+ if (keys.includes("lifetime")) this.itIsNodeReadout = true;
- if (!this.previousValues.hasOwnProperty(tbname)) {
- this.previousValues[tbname] = {};
- }
+ if (!this.previousValues.hasOwnProperty(tbname)) {
+ this.previousValues[tbname] = {};
+ }
- //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);
+ //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);
- for (let i = 0; i < keys.length; i++) {
+ for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
- let value = values[key];
+ let key = keys[i];
+ let value = values[key];
- if (!this.previousValues[tbname].hasOwnProperty(key)) {
- this.previousValues[tbname][key] = { ts: timestamp, value: value };
- continue;
- }
+ if (!this.previousValues[tbname].hasOwnProperty(key)) {
+ this.previousValues[tbname][key] = { ts: timestamp, value: value };
+ continue;
+ }
- // attributeData ==> {voltage: {ts:333333, value:5}}
- let attributeData = this.previousValues[tbname][key];
- let attributeToChange = false;
- if (key in this.attributeChangeLimit) attributeToChange = true;
- let limit = this.attributeChangeLimit[key];
- let timestampDiffToRemoveKey;
+ // attributeData ==> {voltage: {ts:333333, value:5}}
+ let attributeData = this.previousValues[tbname][key];
+ let attributeToChange = false;
+ if (key in this.attributeChangeLimit) attributeToChange = true;
+ let limit = this.attributeChangeLimit[key];
+ let timestampDiffToRemoveKey;
- //this will ensure "node statecode" will be sent just once an hour
- if (this.itIsNodeReadout && key === "statecode") {
- attributeData.value = value;
- this.itIsNodeReadout = false;
- timestampDiffToRemoveKey = 1 * 60 * 60 * 1000; // 1 hour
- }
+ //this will ensure "node statecode" will be sent just once an hour
+ if (this.itIsNodeReadout && key === "statecode") {
+ attributeData.value = value;
+ this.itIsNodeReadout = false;
+ timestampDiffToRemoveKey = 1 * 60 * 60 * 1000; // 1 hour
+ }
- if (key === "twilight_sensor" && value > 100) {
- attributeData.value = value;
- }
+ if (key === "twilight_sensor" && value > 100) {
+ attributeData.value = value;
+ }
- //if edge, master or node version do not change, send just once a day:
- if (["edge_fw_version", "master_node_version", "fw_version"].includes(key)) {
- timestampDiffToRemoveKey = 24 * 60 * 60 * 1000;
- }
+ //if edge, master or node version do not change, send just once a day:
+ if (["edge_fw_version", "master_node_version", "fw_version"].includes(key)) {
+ timestampDiffToRemoveKey = 24 * 60 * 60 * 1000;
+ }
- if (attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit) {
+ if (attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit) {
- let diff = timestamp - attributeData.ts;
- if (!timestampDiffToRemoveKey) timestampDiffToRemoveKey = this.getDiffTimestamp(key);
+ let diff = timestamp - attributeData.ts;
+ if (!timestampDiffToRemoveKey) timestampDiffToRemoveKey = this.getDiffTimestamp(key);
- if (diff > timestampDiffToRemoveKey) {
- attributeData.ts = Date.now();
- //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
- }
- else {
- delete values[key];
- //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
- }
- }
- else {
- attributeData.value = value;
- attributeData.ts = timestamp;
- }
+ if (diff > timestampDiffToRemoveKey) {
+ attributeData.ts = Date.now();
+ //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
+ }
+ else {
+ delete values[key];
+ //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
+ }
+ }
+ else {
+ attributeData.value = value;
+ attributeData.ts = timestamp;
+ }
- }
+ }
- return values;
- }
+ return values;
+ }
}
module.exports = DataToTbHandler;
diff --git a/flow/helper/utils.js b/flow/helper/utils.js
index 9c054aa..57b0f89 100644
--- a/flow/helper/utils.js
+++ b/flow/helper/utils.js
@@ -1,112 +1,170 @@
-function bytesToInt(bytes, numberOfBytes) {
- let buffer = [];
- if (Array.isArray(bytes)) {
- buffer = bytes.slice(0);
- if (numberOfBytes != undefined) {
- buffer = bytes.slice(bytes.length - numberOfBytes);
- }
- }
- else buffer.push(bytes);
-
- let result = 0;
- for (let i = 0; i < buffer.length; i++) {
- result = (result << 8) | buffer[i];
- }
-
- return result >>> 0; //ensure it's an unsigned 32-bit number
-}
-
-function resizeArray(arr, newSize, defaultValue) {
- while (newSize > arr.length)
- arr.push(defaultValue);
- arr.length = newSize;
-}
-
-longToByteArray = function(/*long*/long) {
- // we want to represent the input as a 8-bytes array
- var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
-
- for (var index = 0; index < byteArray.length; index++) {
- var byte = long & 0xff;
- byteArray[index] = byte;
- long = (long - byte) / 256;
- }
-
- return byteArray;
-};
-
-function addDays(date, days) {
- var result = new Date(date);
- result.setDate(result.getDate() + days);
- return result;
-}
-
-/*
-sleep(2000).then(() => {
- // Do something after the sleep!
-
-
-});
-*/
-
-function sleep(time) {
- return new Promise((resolve) => setTimeout(resolve, time));
-}
-
-function isEmptyObject(obj) {
- for (var name in obj) {
- return false;
- }
- return true;
-}
-
-function convertUTCDateToLocalDate(date) {
- var newDate = new Date(date);
- newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
- return newDate;
-}
-
-function addZeroBefore(n) {
- return (n < 10 ? '0' : '') + n;
-}
-
-var convertBase = function() {
-
- function convertBase(baseFrom, baseTo) {
- return function(num) {
- return parseInt(num, baseFrom).toString(baseTo);
-
- };
- }
-
- // binary to decimal
- convertBase.bin2dec = convertBase(2, 10);
-
- // binary to hexadecimal
- convertBase.bin2hex = convertBase(2, 16);
-
- // decimal to binary
- convertBase.dec2bin = convertBase(10, 2);
-
- // decimal to hexadecimal
- convertBase.dec2hex = convertBase(10, 16);
-
- // hexadecimal to binary
- convertBase.hex2bin = convertBase(16, 2);
-
- // hexadecimal to decimal
- convertBase.hex2dec = convertBase(16, 10);
-
- return convertBase;
-}();
-
-module.exports = {
- bytesToInt,
- longToByteArray,
- addDays,
- addZeroBefore,
- resizeArray,
- isEmptyObject,
- sleep,
- convertUTCDateToLocalDate
-}
+function bytesToInt_orig(bytes, numberOfBytes) {
+
+ let buffer = [];
+ if (Array.isArray(bytes)) {
+ buffer = bytes.slice(0);
+ if (numberOfBytes != undefined) {
+ buffer = bytes.slice(bytes.length - numberOfBytes);
+ }
+ }
+ else buffer.push(bytes);
+ //var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+
+ let l = (buffer.length - 1) * 8;
+ let decimal = 0;
+ for (let i = 0; i < buffer.length; i++) {
+ var s = buffer[i] << l;
+ if (l < 8) s = buffer[i]
+ decimal = decimal + s;
+ l = l - 8;
+ }
+ // console.log("decimal utils.js: ", decimal);
+
+ let decimal1 = 0n;
+ for (let i = 0; i < buffer.length; i++) {
+ decimal1 += BigInt(buffer[i]) * (2n ** BigInt((buffer.length - 1 - i) * 8));
+ }
+ // console.log("decimal biging utils.js: ", decimal1);
+ return decimal;
+}
+
+//bytestouintBE
+function bytesToInt(bytes, numberOfBytes) {
+
+ let buffer = [];
+ if (Array.isArray(bytes)) {
+ buffer = bytes.slice(0);
+ if (numberOfBytes != undefined) {
+ buffer = bytes.slice(bytes.length - numberOfBytes);
+ }
+ }
+ else buffer.push(bytes);
+
+ console.log(bytes, buffer);
+
+ let result = 0;
+ for (let i = 0; i < buffer.length; i++) {
+ result = (result << 8) | bytes[i];
+ }
+ // console.log("decimal biging utils.js: ", decimal1);
+
+ console.log("originall: ", bytesToInt_orig(buffer));
+ console.log("uint little endian: ", bytesToUintLE(buffer));
+ console.log('neww: ', result >>> 0);
+ return result >>> 0;
+}
+
+function bytesToUintLE(bytes, numberOfBytes) {
+
+ let buffer = [];
+ if (Array.isArray(bytes)) {
+ buffer = bytes.slice(0);
+ if (numberOfBytes != undefined) {
+ buffer = bytes.slice(bytes.length - numberOfBytes);
+ }
+ }
+ else buffer.push(bytes);
+ //var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+
+ let result = 0;
+ for (let i = buffer.length - 1; i <= 0; i--) {
+ result = (result << 8) | bytes[i];
+ }
+ return result >>> 0;
+}
+
+
+function resizeArray(arr, newSize, defaultValue) {
+ while (newSize > arr.length)
+ arr.push(defaultValue);
+ arr.length = newSize;
+}
+
+longToByteArray = function(/*long*/long) {
+ // we want to represent the input as a 8-bytes array
+ var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
+
+ for (var index = 0; index < byteArray.length; index++) {
+ var byte = long & 0xff;
+ byteArray[index] = byte;
+ long = (long - byte) / 256;
+ }
+
+ return byteArray;
+};
+
+function addDays(date, days) {
+ var result = new Date(date);
+ result.setDate(result.getDate() + days);
+ return result;
+}
+
+/*
+sleep(2000).then(() => {
+ // Do something after the sleep!
+
+
+});
+*/
+
+function sleep(time) {
+ return new Promise((resolve) => setTimeout(resolve, time));
+}
+
+function isEmptyObject(obj) {
+ for (var name in obj) {
+ return false;
+ }
+ return true;
+}
+
+function convertUTCDateToLocalDate(date) {
+ var newDate = new Date(date);
+ newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
+ return newDate;
+}
+
+function addZeroBefore(n) {
+ return (n < 10 ? '0' : '') + n;
+}
+
+var convertBase = function() {
+
+ function convertBase(baseFrom, baseTo) {
+ return function(num) {
+ return parseInt(num, baseFrom).toString(baseTo);
+
+ };
+ }
+
+ // binary to decimal
+ convertBase.bin2dec = convertBase(2, 10);
+
+ // binary to hexadecimal
+ convertBase.bin2hex = convertBase(2, 16);
+
+ // decimal to binary
+ convertBase.dec2bin = convertBase(10, 2);
+
+ // decimal to hexadecimal
+ convertBase.dec2hex = convertBase(10, 16);
+
+ // hexadecimal to binary
+ convertBase.hex2bin = convertBase(16, 2);
+
+ // hexadecimal to decimal
+ convertBase.hex2dec = convertBase(16, 10);
+
+ return convertBase;
+}();
+
+module.exports = {
+ bytesToInt,
+ longToByteArray,
+ addDays,
+ addZeroBefore,
+ resizeArray,
+ isEmptyObject,
+ sleep,
+ convertUTCDateToLocalDate
+}
diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js
index d6d9dad..5852ff3 100644
--- a/flow/modbus_reader.js
+++ b/flow/modbus_reader.js
@@ -16,7 +16,7 @@ exports.readme = `
`;
const modbus = require('jsmodbus');
-const SerialPort = require('serialport');
+const {SerialPort} = require('serialport');
const { timeoutInterval, deviceConfig } = require("../databases/modbus_config");
const { sendNotification } = require('./helper/notification_reporter');
@@ -36,7 +36,6 @@ let mainSocket;
let phases;
//phases where voltage is 0 (set)
let noVoltage;
-let energyToSwitchLamps;
exports.install = function(instance) {
@@ -77,13 +76,8 @@ exports.install = function(instance) {
let obj = this;
- if (this.socket) {
- this.socket.removeAllListeners();
- this.socket = null;
- }
-
- this.socket = new SerialPort("/dev/ttymxc0", {
- baudRate: 9600,
+ this.socket = new SerialPort({path: "/dev/ttymxc0",
+ baudRate: 9600
})
// we create a client for every deviceAddress ( = address) in list and push them into dictionary
@@ -92,11 +86,15 @@ exports.install = function(instance) {
}
this.socket.on('error', function(e) {
- console.log('Modbus_reader: Socket connection error', e); //'ECONNREFUSED' or 'ECONNRESET' ??
+ console.log('socket connection error', e);
+ if (e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') {
+ console.log(exports.title + ' Waiting 10 seconds before trying to connect again');
+ setTimeout(obj.startSocket, 10000);
+ }
});
this.socket.on('close', function() {
- console.log('Modbus_reader: Socket connection closed - Waiting 10 seconds before connecting again');
+ console.log('Socket connection closed ' + exports.title + ' Waiting 10 seconds before trying to connect again');
setTimeout(obj.startSocket, 10000);
});
@@ -117,8 +115,7 @@ exports.install = function(instance) {
this.deviceAddress = dev.deviceAddress; // 1 or 2 or any number
this.device = dev.device; //em340, twilight_sensor
- //if we just start to loop devices from the beginning, or there is just 1 device in config, we wait whole timeoutInterval
- if (this.indexInDeviceConfig == 0 || deviceConfig.length === 1) setTimeout(this.readRegisters, this.timeoutInterval);
+ if (this.indexInDeviceConfig == 0) setTimeout(this.readRegisters, this.timeoutInterval);
else setTimeout(this.readRegisters, DELAY_BETWEEN_DEVICES);
}
@@ -307,12 +304,15 @@ exports.install = function(instance) {
const actualTotalPower = values.total_power;
- if (actualTotalPower > energyToSwitchLamps && this.onNotificationSent == false) {
+ const numberOfNodes = Object.keys(FLOW.GLOBALS.nodesData).length;
+ if (numberOfNodes == 0) numberOfNodes = 20; // to make sure, we send notification if totalPower is more than 300
+
+ if (actualTotalPower > numberOfNodes * 15 && this.onNotificationSent == false) {
sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_on", {}, "", SEND_TO.tb, instance);
this.onNotificationSent = true;
this.offNotificationSent = false;
}
- else if (actualTotalPower <= energyToSwitchLamps && this.offNotificationSent == false) {
+ else if (actualTotalPower <= numberOfNodes * 15 && this.offNotificationSent == false) {
sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_off", {}, "", SEND_TO.tb, instance);
this.onNotificationSent = false;
this.offNotificationSent = true;
@@ -330,9 +330,9 @@ exports.install = function(instance) {
phases = FLOW.GLOBALS.settings.phases;
tbName = FLOW.GLOBALS.settings.rvoTbName;
noVoltage = FLOW.GLOBALS.settings.no_voltage;
- energyToSwitchLamps = FLOW.GLOBALS.settings.energy_to_switch_lamps / 2.5; //half value is enought to show if lamps are turned on or off
- if (deviceConfig.length) mainSocket = new SocketWithClients();
- else console.log("Modbus_reader: no modbus device in configuration");
+ mainSocket = new SocketWithClients();
+
+ console.log("novoltage: ", noVoltage, typeof noVoltage);
// this notification is to show, that flow (unipi) has been restarted
sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance);
diff --git a/flow/variables.txt b/flow/variables.txt
new file mode 100644
index 0000000..e69de29
diff --git a/flow/wsmqttpublish.js b/flow/wsmqttpublish.js
index 0eba804..acc3c33 100644
--- a/flow/wsmqttpublish.js
+++ b/flow/wsmqttpublish.js
@@ -44,9 +44,9 @@ const fs = require('fs');
const mqtt = require('mqtt');
const SEND_TO = {
- debug: 0,
- rpcCall: 1,
- services: 2
+ debug: 0,
+ rpcCall: 1,
+ services: 2
}
//CONFIG
@@ -72,13 +72,13 @@ let sendClientError = true;
process.on('uncaughtException', function(err) {
- errLogger.error('uncaughtException:', err.message)
- errLogger.error(err.stack);
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
- //TODO
- //send to service
+ //TODO
+ //send to service
- //process.exit(1);
+ //process.exit(1);
})
const nosql = NOSQL('tbdata');
@@ -87,362 +87,364 @@ const nosqlBackup = NOSQL('/backup/tbdata');
exports.install = function(instance) {
- var client;
- var opts;
- var clientReady = false;
-
- // wsmqtt status for notification purposes on projects.worksys.io database
- let wsmqttName = null;
- let sendWsStatusVar = null;
- let wsmqtt_status = 'disconnected';
-
- function getWsmqttName(host) {
- if (host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
- else if (host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
- else if (host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
- }
-
- function sendWsStatus() {
- instance.send(SEND_TO.services, { [wsmqttName]: wsmqtt_status });
- }
-
-
- function main() {
- if (!FLOW.dbLoaded) return;
-
- loadSettings();
- clearInterval(sendWsStatus);
- sendWsStatusVar = setInterval(sendWsStatus, 180000);
- }
-
- //set opts according to db settings
- function loadSettings() {
-
- if (instance.options.host !== "") {
- //override settings from database
- var o = instance.options;
- opts = {
- host: o.host,
- port: o.port,
- clientId: o.clientid,
- username: o.username,
- rejectUnauthorized: false,
- resubscribe: false
- };
-
- wsmqttName = getWsmqttName(o.host);
-
- console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
- }
- else {
-
- const SETTINGS = FLOW.GLOBALS.settings;
- backup_on_failure = SETTINGS.backup_on_failure;
- saveTelemetryOnError = backup_on_failure;
-
- restore_from_backup = SETTINGS.restore_from_backup;
- restore_backup_wait = SETTINGS.restore_backup_wait;
-
- let mqtt_host = SETTINGS.mqtt_host;
- let mqtt_clientid = SETTINGS.mqtt_clientid;
- let mqtt_username = SETTINGS.mqtt_username;
- let mqtt_port = SETTINGS.mqtt_port;
-
- opts = {
- host: mqtt_host,
- port: mqtt_port,
- keepalive: 10,
- clientId: mqtt_clientid,
- username: mqtt_username,
- rejectUnauthorized: false,
- resubscribe: false
- };
-
- wsmqttName = getWsmqttName(mqtt_host);
- }
-
- connectToTbServer();
- }
-
- function connectToTbServer() {
- var url = "mqtt://" + opts.host + ":" + opts.port;
- console.log("MQTT URL: ", url);
-
- client = mqtt.connect(url, opts);
-
- client.on('connect', function() {
- instance.status("Connected", "green");
- //monitor.info("MQTT client connected");
-
- sendClientError = true;
- clientReady = true;
- wsmqtt_status = 'connected';
- });
-
- client.on('reconnect', function() {
- 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(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, { qos: 1 });
- instance.send(SEND_TO.rpcCall, { "device": message.device, "id": message.data.id, "RPC response": { "success": true } });
- }
-
- }, () => instance.debug('MQTT: Error parsing data', message));
- }
-
- instance.send(SEND_TO.rpcCall, { "topic": topic, "content": message });
- });
-
- client.on('close', function() {
- clientReady = false;
- wsmqtt_status = 'disconnected';
-
- instance.status("Disconnected", "red");
- instance.send(SEND_TO.debug, { "message": "Client CLOSE signal received !" });
- });
-
- client.on('error', function(err) {
- instance.status("Err: " + err.code, "red");
- instance.send(SEND_TO.debug, { "message": "Client ERROR signal received !", "error": err, "opt": opts });
- if (sendClientError) {
- monitor.info('MQTT client error', err);
- sendClientError = false;
- }
- clientReady = false;
- wsmqtt_status = 'disconnected';
- });
-
- }
-
-
- instance.on("0", _ => {
- main();
- })
+ var client;
+ var opts;
+ var clientReady = false;
+
+ // wsmqtt status for notification purposes on projects.worksys.io database
+ let wsmqttName = null;
+ let sendWsStatusVar = null;
+ let wsmqtt_status = 'disconnected';
+
+ function getWsmqttName(host) {
+ if (host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
+ else if (host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
+ else if (host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
+ }
+
+ function sendWsStatus() {
+ instance.send(SEND_TO.services, { [wsmqttName]: wsmqtt_status });
+ }
+
+
+ function main() {
+ if (!FLOW.dbLoaded) return;
+
+ loadSettings();
+ clearInterval(sendWsStatus);
+ sendWsStatusVar = setInterval(sendWsStatus, 180000);
+ }
+
+ //set opts according to db settings
+ function loadSettings() {
+
+ if (instance.options.host !== "") {
+ //override settings from database
+ var o = instance.options;
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ username: o.username,
+ rejectUnauthorized: false,
+ resubscribe: false
+ };
+
+ wsmqttName = getWsmqttName(o.host);
+
+ console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
+ }
+ else {
+
+ const SETTINGS = FLOW.GLOBALS.settings;
+ backup_on_failure = SETTINGS.backup_on_failure;
+ saveTelemetryOnError = backup_on_failure;
+
+ restore_from_backup = SETTINGS.restore_from_backup;
+ restore_backup_wait = SETTINGS.restore_backup_wait;
+
+ let mqtt_host = SETTINGS.mqtt_host;
+ let mqtt_clientid = SETTINGS.mqtt_clientid;
+ let mqtt_username = SETTINGS.mqtt_username;
+ let mqtt_port = SETTINGS.mqtt_port;
+
+ opts = {
+ host: mqtt_host,
+ port: mqtt_port,
+ keepalive: 10,
+ clientId: mqtt_clientid,
+ username: mqtt_username,
+ rejectUnauthorized: false,
+ resubscribe: false,
+ };
+
+ wsmqttName = getWsmqttName(mqtt_host);
+ }
+
+ connectToTbServer();
+ }
+
+ function connectToTbServer() {
+ var url = "mqtt://" + opts.host + ":" + opts.port;
+ console.log("MQTT URL: ", url);
+
+ client = mqtt.connect(url, opts);
+
+ client.on('connect', function() {
+ instance.status("Connected", "green");
+ //monitor.info("MQTT client connected");
+
+ sendClientError = true;
+ clientReady = true;
+ wsmqtt_status = 'connected';
+ });
+
+ client.on('reconnect', function() {
+ instance.status("Reconnecting", "yellow");
+ clientReady = false;
+ });
+
+ client.on('message', function(topic, message) {
+ // message is type of buffer
+ message = message.toString();
+ if (message[0] === '{') {
+
+ try {
+ message = JSON.parse(message);
+ if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
+ client.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, { qos: 1 });
+ instance.send(SEND_TO.rpcCall, { "device": message.device, "id": message.data.id, "RPC response": { "success": true } });
+ }
+
+ } catch (e) {
+ console.log('MQTT: Error parsing data', e);
+ }
+ }
+
+ instance.send(SEND_TO.rpcCall, { "topic": topic, "content": message });
+ });
+
+ client.on('close', function() {
+ clientReady = false;
+ wsmqtt_status = 'disconnected';
+
+ instance.status("Disconnected", "red");
+ instance.send(SEND_TO.debug, { "message": "Client CLOSE signal received !" });
+ });
+
+ client.on('error', function(err) {
+ instance.status("Err: " + err.code, "red");
+ instance.send(SEND_TO.debug, { "message": "Client ERROR signal received !", "error": err, "opt": opts });
+ if (sendClientError) {
+ monitor.info('MQTT client error', err);
+ sendClientError = false;
+ }
+ clientReady = false;
+ wsmqtt_status = 'disconnected';
+ });
+
+ }
+
+
+ instance.on("0", _ => {
+ main();
+ })
- instance.on('1', function(data) {
+ instance.on('1', 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) {
+ //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();
+ }
- let stringifiedJson = JSON.stringify(data.data);
- client.publish("v1/gateway/telemetry", stringifiedJson, { qos: 1 });
+ let stringifiedJson = JSON.stringify(data.data);
+ client.publish("v1/gateway/telemetry", stringifiedJson, { qos: 1 });
- //backup telemetry
- if (createTelemetryBackup) {
- data.data.id = UID();
- nosqlBackup.insert(data.data);
+ //backup telemetry
+ if (createTelemetryBackup) {
+ data.data.id = UID();
+ nosqlBackup.insert(data.data);
- insertBackupNoSqlCounter++;
- if (insertBackupNoSqlCounter > 150) {
- let options = { compress: true };
- let path = __dirname + "/../databases/backup/tbdata.nosql";
- var stream = new rollers.RollingFileStream(path, noSqlFileSizeLimit, 150, options);
- stream.write("");
- stream.end();
+ insertBackupNoSqlCounter++;
+ if (insertBackupNoSqlCounter > 150) {
+ let options = { compress: true };
+ let path = __dirname + "/../databases/backup/tbdata.nosql";
+ var stream = new rollers.RollingFileStream(path, noSqlFileSizeLimit, 150, options);
+ stream.write("");
+ stream.end();
- insertBackupNoSqlCounter = 0;
- }
- }
+ insertBackupNoSqlCounter = 0;
+ }
+ }
- }
- else {
- //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
- instance.send(SEND_TO.debug, { "message": "Client unavailable. Data not sent !", "data": data.data });
+ }
+ else {
+ //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
+ instance.send(SEND_TO.debug, { "message": "Client unavailable. Data not sent !", "data": data.data });
- if (saveTelemetryOnError) {
- //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
- makeBackupFromDbFile();
+ if (saveTelemetryOnError) {
+ //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
+ makeBackupFromDbFile();
- //write to tb
- data.data.id = UID();
- nosql.insert(data.data);
- }
- }
- });
+ //write to tb
+ data.data.id = UID();
+ nosql.insert(data.data);
+ }
+ }
+ });
- instance.close = function(done) {
- if (clientReady) {
- client.end();
- clearInterval(sendWsStatusVar);
- }
- };
+ instance.close = function(done) {
+ if (clientReady) {
+ client.end();
+ clearInterval(sendWsStatusVar);
+ }
+ };
- function getDbBackupFileCounter(type) {
- var files = fs.readdirSync(__dirname + "/../databases");
+ function getDbBackupFileCounter(type) {
+ var files = fs.readdirSync(__dirname + "/../databases");
- let counter = 0;
- for (var i = 0; i < files.length; i++) {
+ let counter = 0;
+ for (var i = 0; i < files.length; i++) {
- if (files[i] == "tbdata.nosql") continue;
+ if (files[i] == "tbdata.nosql") continue;
- if (files[i].endsWith(".nosql")) {
+ if (files[i].endsWith(".nosql")) {
- let pos = files[i].indexOf(".");
- if (pos > -1) {
+ let pos = files[i].indexOf(".");
+ if (pos > -1) {
- let fileCounter = counter;
- let firstDigit = files[i].slice(0, pos);
+ 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);
+ 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 (type == "max") {
+ if (fileCounter > counter) {
+ counter = fileCounter;
+ }
+ }
+ else if (type == "min") {
+ if (counter == 0) counter = fileCounter;
- if (fileCounter < counter) {
- counter = fileCounter;
- }
- }
- }
- }
+ if (fileCounter < counter) {
+ counter = fileCounter;
+ }
+ }
+ }
+ }
- }
+ }
- if (type == "max") counter++;
+ if (type == "max") counter++;
- return counter;
- }
+ return counter;
+ }
- const makeBackupFromDbFile = async () => {
+ const makeBackupFromDbFile = async () => {
- if (!saveTelemetryOnError) return;
+ if (!saveTelemetryOnError) return;
- //to avoid large file: tbdata.nosql
+ //to avoid large file: tbdata.nosql
- //init value is 0!
- if (insertNoSqlCounter > 0) {
- --insertNoSqlCounter;
- return;
- }
+ //init value is 0!
+ if (insertNoSqlCounter > 0) {
+ --insertNoSqlCounter;
+ return;
+ }
- insertNoSqlCounter = 100;
+ insertNoSqlCounter = 100;
- let source = __dirname + "/../databases/tbdata.nosql";
+ let source = __dirname + "/../databases/tbdata.nosql";
- var stats = fs.statSync(source);
- var fileSizeInBytes = stats.size;
+ var stats = fs.statSync(source);
+ var fileSizeInBytes = stats.size;
- if (fileSizeInBytes > noSqlFileSizeLimit) {
+ if (fileSizeInBytes > noSqlFileSizeLimit) {
- let counter = 1;
- counter = getDbBackupFileCounter("max");
+ let counter = 1;
+ counter = getDbBackupFileCounter("max");
- let destination = __dirname + "/../databases/" + counter + "." + "tbdata.nosql";
+ let destination = __dirname + "/../databases/" + counter + "." + "tbdata.nosql";
- //make backup file
- fs.copyFileSync(source, destination);
- //fs.renameSync(p, p + "." + counter);
+ //make backup file
+ fs.copyFileSync(source, destination);
+ //fs.renameSync(p, p + "." + counter);
- //clear tbdata.nosql
- fs.writeFileSync(source, "");
- fs.truncateSync(source, 0);
+ //clear tbdata.nosql
+ fs.writeFileSync(source, "");
+ fs.truncateSync(source, 0);
- }
- }
+ }
+ }
- const processDataFromDatabase = async () => {
+ const processDataFromDatabase = async () => {
- if (restore_from_backup <= 0) return;
+ if (restore_from_backup <= 0) return;
- //calculate diff
- const now = new Date();
- let currentTime = now.getTime();
- let diff = currentTime - lastRestoreTime;
+ //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;
- }
+ if ((diff / 1000) < restore_backup_wait) {
+ //console.log("*********restore_backup_wait", diff, restore_backup_wait);
+ return;
+ }
- processingData = true;
+ processingData = true;
- //get filename to process
- let counter = getDbBackupFileCounter("min");
+ //get filename to process
+ let counter = getDbBackupFileCounter("min");
- //we have some backup files
- let dataBase = 'tbdata';
+ //we have some backup files
+ let dataBase = 'tbdata';
- var nosql;
- if (counter == 0) dataBase = 'tbdata';
- else dataBase = counter + "." + 'tbdata';
+ var nosql;
+ if (counter == 0) dataBase = 'tbdata';
+ else dataBase = counter + "." + 'tbdata';
- nosql = NOSQL(dataBase);
+ nosql = NOSQL(dataBase);
- //select all data - use limit restore_from_backup
- let records = await promisifyBuilder(nosql.find().take(restore_from_backup));
+ //select all data - use limit restore_from_backup
+ let records = await promisifyBuilder(nosql.find().take(restore_from_backup));
- for (let i = 0; i < records.length; i++) {
- if (clientReady) {
+ for (let i = 0; i < records.length; i++) {
+ if (clientReady) {
- let item = records[i];
- let id = item.id;
+ let item = records[i];
+ let id = item.id;
- if (id !== undefined) {
- //console.log("------------processDataFromDatabase - remove", id, dataBase, i);
+ if (id !== undefined) {
+ //console.log("------------processDataFromDatabase - remove", id, dataBase, i);
- try {
+ try {
- let message = JSON.parse(JSON.stringify(item));
- delete message.id;
+ let message = JSON.parse(JSON.stringify(item));
+ delete message.id;
- client.publish("v1/gateway/telemetry", JSON.stringify(message), { qos: 1 });
+ client.publish("v1/gateway/telemetry", JSON.stringify(message), { qos: 1 });
- //remove from database
- await promisifyBuilder(nosql.remove().where("id", id));
+ //remove from database
+ await promisifyBuilder(nosql.remove().where("id", id));
- } catch (error) {
- //process error
- console.log("processDataFromDatabase", error);
- }
+ } catch (error) {
+ //process error
+ console.log("processDataFromDatabase", error);
+ }
- }
+ }
- }
- else {
- processingData = false;
- return;
- }
- }
+ }
+ else {
+ processingData = false;
+ return;
+ }
+ }
- if (records.length > 0) {
- //clean backup file
- if (counter > 0) nosql.clean();
- }
+ 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();
- }
+ //no data in db, remove
+ if (records.length == 0) {
+ if (counter > 0) nosql.drop();
+ }
- const d = new Date();
- lastRestoreTime = d.getTime();
+ const d = new Date();
+ lastRestoreTime = d.getTime();
- processingData = false;
+ processingData = false;
- }
+ }
- instance.on('options', main);
- //instance.reconfigure();
+ instance.on('options', main);
+ //instance.reconfigure();
};