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 = `
`;
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/ttymxc0",
//"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/ttymxc0 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/ttymxc0", (error, stdout, stderr) => {
// instance.send(instanceSendTo.debug, {"err": error});
// if (error) {
// console.log("--->MODBUS RS485", error, stderr);
// errorHandler.sendMessageToService( exports.title + " sudo halfduplex /dev/ttymxc0 - 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"];
// if we receive data from twilight sensor, we just send it to dido_controller
if(values.hasOwnProperty('twilight_sensor'))
{
delete values["status"];
instance.send(instanceSendTo.di_do_controller, {sender: "modbus_citysys", tbdata: values});
return;
}
//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);
};