exports.id = 'modbus_citysys'; exports.title = 'Modbus_citysys'; exports.version = '1.0.0'; exports.group = 'Worksys'; exports.color = '#2134B0'; exports.input = 1; exports.output = ["red", "white", "blue", "orange"]; exports.click = false; exports.author = 'Jakub Klena'; exports.icon = 'bolt'; exports.options = { edge: "undefined" }; exports.html = `
Edge TB Name
`; exports.readme = `# Energomonitor ## Outputs - *Red* - ERROR output (can connect to filewriter or something) - *White* - STATUS output (answers to your commands, ERRORS and WARNINGS from your commands go both to this and to their own outputs, so they get logged) - *Blue* - TB output (pure data for TB) `; const instanceSendTo = { error: 0, debug: 1, tb: 2, di_do_controller: 3 } const DataToTbHandler = require('./helper/DataToTbHandler.js'); const { sendNotification } = require('./helper/notification_reporter.js'); const dbRelays = TABLE("relays"); const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js'); let tbname; async function loadSettings() { //todo global FLOW.OMS_edgeName is making problem, so we load it here as well, it should not be let responseRelays = await promisifyBuilder(dbRelays.find()); FLOW.OMS_edgeName = responseRelays[0]["tbname"]; tbname = FLOW.OMS_edgeName; } loadSettings(); exports.install = function(instance) { const SerialPort = require('serialport'); const { exec } = require('child_process'); const fs = require("fs"); const filepath = F.path.root("saved_data/modbus_settings"); const backup_filepath = F.path.root("saved_data/modbus_settings_backup"); const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js'); const errorHandler = new ErrorToServiceHandler(); let receivedDataArray = []; instance.CONFIG = { "isRunning": false, "debug": true, "timeoutTime": 10000, "msgWaitTime": 1000, "port": "/dev/ttymxc1", //"port_options": "stty -F /dev/ttymxc1 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke" "port_options": "stty -F /dev/ttymxc1 9600 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke" }; let PRIVATEVARS = { "errBuffer": [], // Buffer for error messages "tbBuffer": [], // Buffer for TB push messages "device_index": 0, "cmd_index": -1, "devices": [ /*{ "name": "Elektrometer 1", "tb_name": "EOzNMgZ9n43qPbjXmy7zwdA2DKdYvW5e6pxGRrVa", "type": "EM111", "address": 1, "data":[], "cmd":[], "timeoutcount":0, "status":"virtual" },*/ // { // "name": "Elektrometer 2", // "tb_name": "pJX1ObgmqGZ54DMyYL7aDdkEVdve38WKRzwjNrQ9", // "type": "EM111", // "address": 2, // "data":[], // "cmd":[], // "timeoutcount":0, // "status":"virtual" // }, // { // "name": "Elektrometer 3", // "tb_name": "XRvmwNz8QPblKp41GD7lKVkJrLVYoBO92dMegn6W", // "type": "EM111", // "address": 3, // "data":[], // "cmd":[], // "timeoutcount":0, // "status":"virtual" // }, // { // "name": "Elektrometer 4", // "tb_name": "oRO8rjaBDy21qPQJzW7oD9ApK3xmNleVZg9Ed4Gw", // "type": "EM111", // "address": 4, // "data":[], // "cmd":[], // "timeoutcount":0, // "status":"virtual" // }, { "name": "Elektrometer 1", "tb_name": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", "type": "EM340", "address": 1, "data":[], "cmd":[], "timeoutcount":0, "status":"virtual" } ], "cmd_tables": [ { "type":"EM340", "cmd":[ { "name": "Voltage L1", "tb_name": "a", "register": 0, "size": 2, "multiplier": 0.1 }, { "name": "Voltage L2", "tb_name": "b", "register": 2, "size": 2, "multiplier": 0.1 }, { "name": "Voltage L3", "tb_name": "c", "register": 4, "size": 2, "multiplier": 0.1 }, { "name": "Current L1", "tb_name": "d", "register": 12, "size": 2, "multiplier": 0.001 }, { "name": "Current L2", "tb_name": "e", "register": 14, "size": 2, "multiplier": 0.001 }, { "name": "Current L3", "tb_name": "f", "register": 16, "size": 2, "multiplier": 0.001 } // { // "name": "Power factor", // "tb_name": "power_factor", // "register": 14, // "size": 1, // "multiplier": 0.001 // }, // { // "name": "Frequency", // "tb_name": "frequency", // "register": 15, // "size": 1, // "multiplier": 0.1 // }, // { // "name": "Energy", // "tb_name": "consumption", // "register": 16, // "size": 2, // "multiplier": 0.1 // } ] } ] }; let ERRWEIGHT = { EMERGENCY: "emergency", // System unusable ALERT: "alert", // Action must be taken immidiately CRITICAL: "critical", // Component unable to function ERROR: "error", // Error, but component able to recover from it WARNING: "warning", // Possibility of error, system running futher NOTICE: "notice", // Significant message but not an error, things user might want to know about INFO: "informational", // Info DEBUG: "debug" // Debug - only if CONFIG.debug is enabled }; instance.currentData = function(){ let resp = []; for (let f = 0; f < PRIVATEVARS.devices.length; f++){ let dev = PRIVATEVARS.devices[f]; for (let e = 0; e < dev.data.length; e++){ let d = dev.data[e]; resp.push({ "name": dev.name+" - "+d.name, "value": d.value }); } } return resp; }; instance.configList = function(){ let resp = []; /*let data = PRIVATEVARS.feeds; for (let a = 0; a < data.length; a++){ for (let i = 0; i < instance.CONFIG.feeds.length; i++){ let feed = instance.CONFIG.feeds[i]; if (feed.name === data[a].id){ for (let b = 0; b < data[a].streams.length; b++){ for (let j = 0; j < feed.streams.length; j++){ let stream = feed.streams[j]; if (stream.name === data[a].streams[b].id){ data[a].streams[b]["exists"] = true; data[a].streams[b]["currently"] = stream; } } } } } } resp.push({ "name":"Device manager", "icon":"tasks", "_show":false, "js_func":"energoDevManager", "data": data });*/ return resp; } let timeoutInterval = null; let msgWaitInterval = null; let port = null; let myEdge = "undefined"; let starter = null; instance.status("Loading...", "red"); instance.availableCommands = [ { "name": "Status", "cmd": "qStatus", "icon": "stream", "func": function(body){ let a = true; if (timeoutInterval === null){ a = false; } let b = true; if (msgWaitInterval === null){ b = false; } let st = { "isRunning":instance.CONFIG.isRunning, "timeoutInterval":a, "msgWaitInterval":b, "CONFIG":instance.CONFIG }; return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": st }; } }, { "name": "Start Reading", "cmd": "sStart", "icon": "play", "func": function(body){ /*if (running === false){ startCmdWaitInterval(); running = true; return "Reading started !"; } else { return "Reading already active !"; }*/ return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": "WIP" }; } }, { "name": "Stop Reading", "cmd": "sStop", "icon": "stop", "func": function(body){ /*if (running === true){ stopCmdWaitInterval(); stopTimeoutInterval(); running = false; return "Reading stopped !"; } else { return "Reading already inactive !"; }*/ return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": "WIP" }; } }, { "name": "Read current data", "cmd": "qCurrentData", "icon": "chart-bar", "func": function(body){ let resp = instance.currentData(); return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": resp }; } }, { "name": "Save current config", "cmd": "saveConfig", "icon": "save", "func": function(body){ instance.set("config", JSON.stringify(instance.CONFIG)); instance.set("private", JSON.stringify(PRIVATEVARS)); return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": "done" }; } }, { "name": "Toggle debug", "cmd": "sDebug", "icon": "comment-dots", "func": function(body){ if (instance.CONFIG.debug){ instance.CONFIG.debug = false; instance.set("config", JSON.stringify(instance.CONFIG)); return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": "debug OFF" }; } else { instance.CONFIG.debug = true; instance.set("config", JSON.stringify(instance.CONFIG)); return { "type": "ok", "timestamp": humanReadableTimeAndDate(), "resp": "debug ON" }; } } } ]; function saveData(){ if (checkFile(filepath)){ let content = undefined; try { content = fs.readFileSync(filepath); } catch (err){ console.log("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message}); //sendError("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message}); } if (content !== undefined){ try { fs.writeFileSync(backup_filepath, content, "utf8"); } catch (err) { //sendError("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to save backup of configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message}); console.log("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to save backup of configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message}); } } } let a = { "config":instance.CONFIG, "private":PRIVATEVARS }; try { fs.writeFileSync(filepath, JSON.stringify(a), "utf8"); } catch (err) { //sendError("saveData", myEdge, ERRWEIGHT.CRITICAL, "Unable to save configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message}); console.log("saveData", myEdge, ERRWEIGHT.CRITICAL, "Unable to save configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message}); } } function loadData(){ let content = undefined; //console.log(filepath); if (checkFile(filepath)){ try { content = fs.readFileSync(filepath); } catch (err){ //sendError("loadData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message}); console.log("loadData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message}); } } else { if (checkFile(backup_filepath)){ try { content = fs.readFileSync(backup_filepath); } catch (err){ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "Unable to read backup configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message}); console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "Unable to read backup configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message}); } if (content !== undefined){ //sendError("loadData", myEdge, ERRWEIGHT.WARNING, "No configuration, loading from backup !", {"name":instance.name, "id":instance.id}); console.log("loadData", myEdge, ERRWEIGHT.WARNING, "No configuration, loading from backup !", {"name":instance.name, "id":instance.id}); } } else { //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "No configuration, not even backup !", {"name":instance.name, "id":instance.id}); console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "No configuration, not even backup !", {"name":instance.name, "id":instance.id, "filepath": filepath}); } } if (content !== undefined){ let a = JSON.parse(content); instance.send(instanceSendTo.debug, a); let c = a.config; let p = a.private; if (c === undefined){ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "Configuration not found !", {"name":instance.name, "id":instance.id}); console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "Configuration not found !", {"name":instance.name, "id":instance.id}); instance.status("Error - no config", "red"); } else if (p === undefined){ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "Privatevars not found !", {"name":instance.name, "id":instance.id}); console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "Privatevars not found !", {"name":instance.name, "id":instance.id}); instance.status("Error - no private vars", "red"); } else { instance.CONFIG = c; PRIVATEVARS = p; // Daj kazdemu device jeho tabulku prikazu for (let i = 0; i < PRIVATEVARS.devices.length; i++){ let device = PRIVATEVARS.devices[i]; for (let j = 0; j < PRIVATEVARS.cmd_tables.length; j++){ let table = PRIVATEVARS.cmd_tables[j]; if (device.type === table.type){ PRIVATEVARS.devices[i].cmd = table.cmd; } } } if (myEdge === "undefined"){ instance.status("Unconfigured", "red"); } else { instance.status("Running", "green"); startCmdWaitInterval(); instance.CONFIG.isRunning = true; console.log("modbus loaded: ", PRIVATEVARS.devices); } } } } function checkFile(name){ try { fs.accessSync(name, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK); return true; } catch (err) { return false; } } //Zapina slucku vycitavania dat function readDeviceData(){ stopCmdWaitInterval(); // let tbname = FLOW.OMS_edgeName; // Check port existance if (port === null) { port = new SerialPort(instance.CONFIG.port); port.on('error', function(err) { //logger.debug("rsPort opened error - failed", err.message); //instance.send(instanceSendTo.debug, err.message); errorHandler.sendMessageToService( exports.title + " MODBUS RS485 open - failed: " + err.message); }) port.on('open', function() { console.log("--->MODBUS RS485 READY - port opened"); exec("sudo halfduplex /dev/ttymxc1", (error, stdout, stderr) => { instance.send(instanceSendTo.debug, {"err": error}); if (error) { console.log("--->MODBUS RS485", error, stderr); errorHandler.sendMessageToService( exports.title + " sudo halfduplex /dev/ttymxc1 - failed: " + error); } }); exec(instance.CONFIG.port_options, (error, stdout, stderr) => { instance.send(instanceSendTo.debug, {"stdout":stdout,"stderr":stderr,"err":error}); if (error) { console.log("--->MODBUS RS485", error, stderr); errorHandler.sendMessageToService( exports.title + " " + instance.CONFIG.port_options + " - failed: " + error); } }); }); port.on('data', receivedData); //sendError("readDeviceData", myEdge, ERRWEIGHT.DEBUG, "Serial port open!", {}); //console.log("-->MODBUS readDeviceData", myEdge, ERRWEIGHT.DEBUG, "Serial port open!", {}); startCmdWaitInterval(); return; // Cakame na port aby sa spravne otvoril a rozbehol } // Skontroluj existenciu device listu if (PRIVATEVARS.devices.length > 0){ // Ponastavuj indexy PRIVATEVARS.cmd_index++; if (PRIVATEVARS.cmd_index >= PRIVATEVARS.devices[PRIVATEVARS.device_index].cmd.length){ // Kedže všetky príkazy pre daný device sú vybavené, je treba odoslat vyčítané data do TB updateDataInTB(); PRIVATEVARS.cmd_index = 0; PRIVATEVARS.device_index++; if (PRIVATEVARS.device_index >= PRIVATEVARS.devices.length){ PRIVATEVARS.device_index = 0; } } let device = PRIVATEVARS.devices[PRIVATEVARS.device_index]; // Skontroluj existenciu príkazú pre daný device type if (device.cmd.length < 1){ //sendError("readDeviceData", tbname, ERRWEIGHT.ERROR, "No commands for this device type !", {"type": device.type}); console.log("readDeviceData", tbname, ERRWEIGHT.ERROR, "No commands for this device type !", {"type": device.type}); startCmdWaitInterval(); return; } // Odešli nasledujúci príkaz sendCommand(); } else { instance.CONFIG.isRunning = false; //sendError("readDeviceData", myEdge, ERRWEIGHT.CRITICAL, "Modbus has no devices registered!", {}); console.log("modbus_citys: readDeviceData", myEdge, ERRWEIGHT.CRITICAL, "Modbus has no devices registered!", {}); } } function readingTimeouted(){ stopCmdWaitInterval(); stopTimeoutInterval(); // let tbname = FLOW.OMS_edgeName; let device = PRIVATEVARS.devices[PRIVATEVARS.device_index]; let com = device.cmd[PRIVATEVARS.cmd_index]; //sendError("readingTimeouted", tbame, ERRWEIGHT.WARNING, "Reading timeouted !", {"device": device.address, "cmd": com.register}); console.log("modbus_citys: readingTimeouted", tbname, ERRWEIGHT.WARNING, "Reading timeouted !", {"device": device.address, "cmd": com.register}); device.timeoutcount++; //console.log("device.timeoutcount", device.timeoutcount); if (device.timeoutcount === 16) { //sendError("modbus_citys: readingTimeouted", tbname, ERRWEIGHT.CRITICAL, "Electrometer is not responding - reading timeouted", ""); sendNotification("modbus_citys: readingTimeouted", tbname, "electrometer_is_not_responding", {}, "", instanceSendTo.tb, instance ); if (device.status === "OK"){ device.status === "NOK"; } } startCmdWaitInterval(); } function receivedData(data){ //let array = [...data]; //console.log("received data", array); // let tbname = FLOW.OMS_edgeName; //!if received data are less than 9 bytes, we store it in array variable and return. than we concatenate second incoming // data and then length of array is 9 receivedDataArray = [...receivedDataArray, ...data]; //if (array.length < 9) return; let l = receivedDataArray.length; //console.log("received",receivedDataArray, l) if ( l < 7 || l > 9 || l == 8 ) return; let device = PRIVATEVARS.devices[PRIVATEVARS.device_index]; let com = device.cmd[PRIVATEVARS.cmd_index]; if (device.timeoutcount > 16) { //sendError("Modbus_citysys: receivedData", tbname, ERRWEIGHT.NOTICE, "Electrometer is responding again", ""); sendNotification("modbus_citys: receivedData", tbname, "electrometer_is_responding_again", {}, "", instanceSendTo.tb, instance ); } device.timeoutcount = 0; if ((l == 7 && com.size != 1) || ( l == 9 && com.size != 2)) return; stopTimeoutInterval(); //sendError("receivedData", tbname, ERRWEIGHT.DEBUG, "Received data !", {"cmd": receivedDataArray}); //console.log("receivedData", tbname, ERRWEIGHT.DEBUG, "Received data !", {"cmd": receivedDataArray}); // Skontroluj či sedí počet bytú v správe //console.log("com size", com.size*2, "array2", receivedDataArray[2]); if (receivedDataArray[2] !== (com.size*2)){ //sendError("receivedData", tbname, ERRWEIGHT.ERROR, "Received data of incorrect size !", {"expected": (com.size*2), "received": receivedDataArray[2], "cmd": com.register, "whole_msg": receivedDataArray}); console.log("modbus_citys: receivedData", tbname, ERRWEIGHT.ERROR, "Received data of incorrect size !", {"expected": (com.size*2), "received": receivedDataArray[2], "cmd": com.register, "whole_msg": receivedDataArray}); startTimeoutInterval(); } else { // Konvertuj raw data na human readable let v = (receivedDataArray[3] << 8) | receivedDataArray[4]; if (com.size == 2){ v = v | (receivedDataArray[5] << 24) | (receivedDataArray[6] << 16); } v = Math.round((v * com.multiplier) * 100) / 100; // Pokad device nemá ešte žádné hodnoty vyčítané, pushni túto hodnotu do pola if (device.data.length < 1){ device.data.push({ // Vždy ked správne zakomunikuje obnov status na OK "changed": true, "name": "status", "value": "OK" }); device.data.push({ "changed": true, "name": com.tb_name, "value": v }); } else { // Kedže už neco v poli má, kukni sa či je tam aj táto hodnota let found = false; for (let i = 0; i < device.data.length; i++){ let d = device.data[i]; if (d.name == "status"){ // Ked natrefíš na status (vždy tam musí byt) prepíš ho na OK lebo zakomunikoval správne device.data[i].changed = true; device.data[i].value = "OK"; } if (d.name == com.tb_name){ found = true; device.data[i].changed = true; device.data[i].value = v; } } // Pole existuje, ale táto hodnota tam neni, pridaj ju if (found === false){ device.data.push({ "changed": true, "name": com.tb_name, "value": v }); } } //Správne sme prijali odpoveď, je čas na další msg startCmdWaitInterval(); } //console.log('received data array', receivedDataArray); receivedDataArray = []; } function updateDataInTB(){ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index]; // console.log("---- MB device", device); // console.log("---MB device data", device.data); let values = ""; for (let i = 0; i < device.data.length; i++){ let data = device.data[i]; if (data.changed){ if (values !== ""){ values += ", "; } if (data.name === "status"){ values += "\""+data.name+"\":\""+data.value+"\""; // This makes sure, that if this device doesn’t respond even once in next reading cycle, it will be marked as NOK device.data[i].changed = true; device.data[i].value = "NOK"; } else { values += "\""+data.name+"\":"+data.value; device.data[i].changed = false; } } } //console.log("values modbus", values); if (values !== ""){ // let tbname = FLOW.OMS_edgeName; // if(tbname == "" || tbname === undefined ) // { // console.log("!!!!!!FLOW.OMS_edgeName is empty - 1"); // return; // } let tbmsg = "{\"" + tbname + "\":[{\"ts\":"+Date.now()+", \"values\":{"+values+"}}] }"; tbmsg = JSON.parse(tbmsg); values = tbmsg[tbname][0]["values"]; //console.log("modbus", Object.keys(values)); //sum Phase_1_power, Phase_2_power, Phase_3_power (if one of them is undefined, we handle it) const numOr0 = n => isNaN(n) ? 0 : n; let calculated_total_power = [values["Phase_1_power"], values["Phase_2_power"], values["Phase_3_power"]].reduce((a, b) => numOr0(a) + numOr0(b)); values["total_power"] = parseFloat(calculated_total_power.toFixed(2)); tbmsg[tbname][0]["values"] = values; Object.keys(values).map(singleValue => { if (["Phase_1_voltage", "Phase_2_voltage", "Phase_3_voltage"].includes(singleValue)) { let l = singleValue.split("_"); let phase = parseInt(l[1]); if(FLOW.OMS_no_voltage == undefined) FLOW.OMS_no_voltage = new Set(); if(values[singleValue] == 0) { sendNotification("modbus_citys: updateDataInTB", tbname, "no_voltage_detected_on_phase", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase ); FLOW.OMS_no_voltage.add(phase); } else { FLOW.OMS_no_voltage.delete(phase); sendNotification("modbus_citys: updateDataInTB", tbname, "voltage_on_phase_has_been_restored", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase); } } }) sendThingsBoard(tbmsg); } } let electrometerNotResponding = 0; function sendCommand(){ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index]; let com = device.cmd[PRIVATEVARS.cmd_index]; let array = [device.address, 3, ((com.register >> 8) & 0xFF), (com.register & 0xFF), ((com.size >> 8) & 0xFF), (com.size & 0xFF)]; array = modbusCRC(array); //console.log('---device--', device); //console.log('---device type--', device.type); //sendError("sendCommand", device.tb_name, ERRWEIGHT.DEBUG, "Sending command !", {"cmd": array}); //console.log("sendCommand", device.tb_name, ERRWEIGHT.DEBUG, "Sending command !", {"cmd": array}); // let tbname = FLOW.OMS_edgeName; // if(tbname == "" || tbname === undefined ) // { // console.log("!!!!!!FLOW.OMS_edgeName is empty - 2"); // return; // } startTimeoutInterval(); port.write(Buffer.from(array), function(err) { //! poslany command //console.log("poslany tento commant", array, err, device.type); if (err) { stopTimeoutInterval(); stopCmdWaitInterval(); // elektromer neodpoveda viac ako 5 minut (15 commands za minutu sa posiela) if (device.type === "EM111" || device.type === "EM340") { electrometerNotResponding++; if (electrometerNotResponding > 15 && electrometerNotResponding < 17) { //sendError("Modbus_citys: sendCommand", tbname, ERRWEIGHT.CRITICAL, "Electrometer is not responding", {"err": err.message, "info": "No response more than 5 minutes"}); sendNotification("modbus_citys: sendCommand", tbname, "electrometer_is_not_responding", {}, {"err": err.message, "info": "No response more than 5 minutes"}, instanceSendTo.tb, instance ); let tbmsg = { [tbname]: [ { "ts": Date.now(), "values": { "status": "NOK" } } ] } sendThingsBoard(tbmsg) } } return; } if (device.type === "EM111") { if (electrometerNotResponding > 15) { //sendError("Modbus_citys: sendCommand", tbname, ERRWEIGHT.NOTICE, "Electrometer is responding again", ""); sendNotification("modbus_citys: sendCommand", tbname, "electrometer_is_responding_again", {}, "", instanceSendTo.tb, instance ); } electrometerNotResponding = 0; } }); } function modbusCRC(array){ let crc = 0xFFFF; for (let i = 0; i < array.length; i++){ let b = array[i]; crc = crc ^ b; for (let j = 8; j>0; j--){ if ((crc & 0x0001) != 0){ crc = crc >> 1; crc = crc ^ 0xA001; } else { crc = crc >> 1; } } } array.push(crc & 0xFF); array.push((crc >> 8) & 0xFF); return array; } instance.on('data', function(flowdata) { console.log("flowdata on data", flowdata); sendStatus({"CONFIG": instance.CONFIG, "PRIVATEVARS":PRIVATEVARS}) }); instance.reconfigure = function() { //TODO remove ftom options myEdge = instance.options.edge; if (starter === null){ starter = setInterval(function(){ loadData(); clearInterval(starter); starter = null; }, 5000); } }; instance.close = function() { // close sockets and such }; function sendError(func, device, weight, str, extra){ if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){ return; // Allow debug messages only if CONFIG.debug is active } let content = { "type": weight, "status": "new", "source": { "func":func, "component":instance.id, "component_name":instance.name, "edge":myEdge }, "message":str, "message_data": extra }; let msg = {}; msg[device] = [ { "ts": Date.now(), "values": { "_event":content } } ]; // Msg can be outputted from components only after configuration /*if (canSendErrData()){ sendBufferedErrors(); } else { bufferError(msg); }*/ instance.send(instanceSendTo.tb, msg); // Even if error server is unavailable, send this message to output, for other possible component connections function sendBufferedErrors(){ if (PRIVATEVARS.errBuffer === undefined){ console.log("errBuffer undefined"); console.log("private: ", PRIVATEVARS); } console.log("errBuffer size: ", PRIVATEVARS.errBuffer.length); if (PRIVATEVARS.errBuffer.length > 0){ for (let i = 0; i < PRIVATEVARS.errBuffer.length; i++){ instance.send(instanceSendTo.error, PRIVATEVARS.errBuffer[i]); } PRIVATEVARS.errBuffer = []; //Clear the buffer saveData(); } } function bufferError(msg){ PRIVATEVARS.errBuffer.push(msg); saveData(); } } function canSendErrData(){ //if (FLOW.errServerAvailable) return true; //else // return false; } function sendStatus(str){ instance.send(instanceSendTo.debug, str); } function sendThingsBoard(obj){ // Msg can be outputted from components only after configuration /*if (canSendTbData()){ sendBufferedTB(); } else { console.log("cant send data"); bufferTB(str); }*/ //console.log("send thingsboard", str); //console.log("FLOW.OMS_edgeName", FLOW.OMS_edgeName, obj); if(obj.hasOwnProperty(FLOW.OMS_edgeName) && FLOW.OMS_edgeName != "") { //send it to di_do_controller instance.send(instanceSendTo.di_do_controller, {sender: "modbus_citysys", tbdata: obj}); } // else { instance.send(instanceSendTo.tb, obj); // Even if TB server is unavailable, send this message to output, for other possible component connections } //instance.send(2, str); // Even if TB server is unavailable, send this message to output, for other possible component connections function sendBufferedTB(){ if (PRIVATEVARS.tbBuffer.length > 0){ console.log("sending buffered: ", PRIVATEVARS.tbBuffer.length ); for (let i = 0; i < PRIVATEVARS.tbBuffer.length; i++){ instance.send(instanceSendTo.tb, PRIVATEVARS.tbBuffer[i]); } PRIVATEVARS.tbBuffer = []; //Clear the buffer saveData(); } } function bufferTB(str){ PRIVATEVARS.tbBuffer.push(str); saveData(); } } function canSendTbData(){ //if (FLOW.tbAvailable) return true; //else // return false; } function startTimeoutInterval(){ if (!timeoutInterval){ timeoutInterval = setInterval(readingTimeouted, instance.CONFIG.timeoutTime); } } function stopTimeoutInterval(){ if (timeoutInterval){ clearInterval(timeoutInterval); timeoutInterval = null; } } function startCmdWaitInterval(){ if (!msgWaitInterval){ msgWaitInterval = setInterval(readDeviceData, instance.CONFIG.msgWaitTime); } } function stopCmdWaitInterval(){ if (msgWaitInterval){ clearInterval(msgWaitInterval); msgWaitInterval = null; } } instance.on('options', instance.reconfigure); instance.reconfigure(); // LAST SECTION FOR COMMON FUNCTIONS function humanReadableTimeAndDate(){ let date_ob = new Date(); let date = ("0" + date_ob.getDate()).slice(-2); let month = ("0" + (date_ob.getMonth() + 1)).slice(-2); let year = date_ob.getFullYear(); let hours = ("0" + date_ob.getHours()).slice(-2); let minutes = ("0" + date_ob.getMinutes()).slice(-2); let seconds = ("0" + date_ob.getSeconds()).slice(-2); return date+"."+month+"."+year+" "+hours+":"+minutes+":"+seconds; } if (starter === null){ starter = setInterval(function(){ loadData(); clearInterval(starter); starter = null; }, 5000); } //setTimeout(loadData, 5000); };