citysys-flowserver/flow/modbus_citysys.js

1127 lines
35 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 = `<div class="padding">
<div class="row">
<div class="col-md-6">
<div data-jc="textbox" data-jc-path="edge" data-jc-config="placeholder:undefined;required:true" class="m">Edge TB Name</div>
</div>
</div>
</div>`;
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 doesnt 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);
};