Actual code running on CEZ rvo

This commit is contained in:
rasta5man 2024-04-13 21:46:15 +02:00
parent 86619fbcff
commit a30a8588a7
12 changed files with 2841 additions and 1828 deletions

3
config
View file

@ -1,4 +1,5 @@
name : Total.js Flow name : Total.js Flow
default_timezone : Europe/Bratislava default_timezone : Europe/Bratislava
// Packages settings // Packages settings
@ -6,7 +7,7 @@ package#flow (Object) : { url: '/' }
table.relays : line:number|tbname:string|contactor:number|profile:string table.relays : line:number|tbname:string|contactor:number|profile:string
table.nodes : node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean table.nodes : node:number|tbname:string|line:number|dimming:number|profile:string|processed:boolean|status:boolean
table.settings : rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number table.settings : rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number
table.pins : pin:string|type:string|line:number table.pins : pin:string|type:string|line:number
table.notifications : key:string|weight:string|sk:string|en:string table.notifications : key:string|weight:string|sk:string|en:string

View file

@ -1,113 +0,0 @@
const timeoutInterval = 300000;
const deviceConfig = [
{
device: "em340",
deviceAddress: 1,
stream: [
{
"tbAttribute": "Phase_1_voltage",
"register": 0,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "Phase_2_voltage",
"register": 2,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "Phase_3_voltage",
"register": 4,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "Phase_1_current",
"register": 12,
"size": 2,
"multiplier": 0.001
},
{
"tbAttribute": "Phase_2_current",
"register": 14,
"size": 2,
"multiplier": 0.001
},
{
"tbAttribute": "Phase_3_current",
"register": 16,
"size": 2,
"multiplier": 0.001
},
{
"tbAttribute": "Phase_1_power",
"register": 18,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "Phase_2_power",
"register": 20,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "Phase_3_power",
"register": 22,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "total_power",
"register": 40,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "total_energy",
"register": 52,
"size": 2,
"multiplier": 0.1
},
{
"tbAttribute": "Phase_1_pow_factor",
"register": 46,
"size": 1,
"multiplier": 0.001
},
{
"tbAttribute": "Phase_2_pow_factor",
"register": 47,
"size": 1,
"multiplier": 0.001
},
{
"tbAttribute": "Phase_3_pow_factor",
"register": 48,
"size": 1,
"multiplier": 0.001
},
{
"tbAttribute": "power_factor",
"register": 49,
"size": 1,
"multiplier": 0.001
}
]
},
{
device: "twilight_sensor",
deviceAddress: 2,
stream: [
{
"tbAttribute": "twilight_sensor",
"register": 60,
"size": 2,
"multiplier": 1
}
]
}
];
module.exports = { timeoutInterval, deviceConfig };

View file

@ -89,9 +89,13 @@ const gmtOffset = 0;
//priorities for registers //priorities for registers
let priorities = []; let priorities = [];
let minutes = 1; let minutes = 0.2;
priorities["0"] = minutes;
priorities["1"] = minutes; priorities["1"] = minutes;
priorities["42"] = minutes;
minutes = 1;
priorities["0"] = minutes;
priorities["104"] = minutes;
minutes = 5; minutes = 5;
priorities["74"] = minutes; priorities["74"] = minutes;
@ -110,9 +114,10 @@ priorities["80"] = minutes;
priorities["8"] = minutes; priorities["8"] = minutes;
priorities["3"] = minutes; priorities["3"] = minutes;
priorities["89"] = minutes; priorities["89"] = minutes;
priorities["95"] = minutes;
//prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app //prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app
let listOfCommands = [0,1,3,6,7,8,74,75,76,77,78,79,80,84,87,89]; let listOfCommands = [0,1,3,6,7,8,42,74,75,76,77,78,79,80,84,87,89,95,104];
//1 - dimming //1 - dimming
@ -236,9 +241,31 @@ function processNodeProfile(node)
logger.debug("processNodeProfile: start - set profile for ", node, profile); logger.debug("processNodeProfile: start - set profile for ", node, profile);
let nodeProfile; let nodeProfile;
try{ try {
nodeProfile = JSON.parse( profile ); nodeProfile = JSON.parse( profile );
if(Object.keys(nodeProfile).length === 0) throw ("profile is not defined");
if(Object.keys(nodeProfile).length === 0) {
//ak nie je pre node nastaveny profil, nastavime dimming nodu podla hodnoty v nodes.table
console.log('____________ttttt', nodeObj.tbname, node, nodeObj.dimming)
let params = getParams(priorityTypes.high_priority);
params.type = "cmd";
params.tbname = nodeObj.tbname;
params.address = node;
params.register = 1;//dimming
params.recipient = 1;//slave
params.byte4 = nodeObj.dimming;
params.rw = 1;//write
params.timestamp = priorityTypes.high_priority;
params.info = 'setNodeDimming';
//params.debug = true;
logger.debug("dimming", params);
tasks.push(params);
throw ("profile is not defined");
}
} catch (error) {} } catch (error) {}
//test reset profilu //test reset profilu
@ -320,6 +347,21 @@ function processNodeProfile(node)
logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node); logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node);
// "intervals": [
// {
// "cct": 3000,
// "value": 0,
// "end_time": "17:50",
// "start_time": "13:00"
// },
// {
// "cct": 3000,
// "value": 100,
// "end_time": "21:30",
// "start_time": "17:50"
// }
// ]
//TS1 Time point a TS1 Time Point Levels //TS1 Time point a TS1 Time Point Levels
let register = 9; let register = 9;
for(let i = 0; i < nodeProfile.intervals.length; i++) for(let i = 0; i < nodeProfile.intervals.length; i++)
@ -327,7 +369,7 @@ function processNodeProfile(node)
let obj = nodeProfile.intervals[i]; let obj = nodeProfile.intervals[i];
//let timePoint = obj.time_point; //let timePoint = obj.time_point;
let dim_value = obj.value; let dim_value = obj.value;
let cct = obj.cct;
//Reg 9 až Reg 40 //Reg 9 až Reg 40
@ -373,13 +415,18 @@ function processNodeProfile(node)
register++; register++;
timestamp++; timestamp++;
// ked zapisujeme Time point levels, zapisujeme:
// byte1 = 1, byte2 = CCT_H, byte3 = CCT_L, byte 4 = dimming
byte2 = Math.floor(cct/256);
byte3 = cct - (byte2 * 256);
params = getParams(priorityTypes.node_cmd); params = getParams(priorityTypes.node_cmd);
params.type = "set_node_profile"; params.type = "set_node_profile";
params.address = node; params.address = node;
params.byte1 = 0; params.byte1 = 1;
params.byte2 = 0; params.byte2 = byte2;
params.byte3 = 0;//ss params.byte3 = byte3;
params.byte4 = parseInt(dim_value) + 128;// params.byte4 = parseInt(dim_value) + 128;
params.recipient = 1; params.recipient = 1;
params.register = register; params.register = register;
params.rw = 1;//write params.rw = 1;//write
@ -612,7 +659,7 @@ const instanceSendTo = {
debug: 0, debug: 0,
tb: 1, tb: 1,
http_response: 2, http_response: 2,
dido_controller: 3, di_do_controller: 3,
infoSender: 4 infoSender: 4
} }
@ -783,17 +830,44 @@ exports.install = function(instance) {
for (let k in nodesData) { for (let k in nodesData) {
//node:number|tbname:string|line:number|profile:string|processed:boolean //node:number|tbname:string|line:number|profile:string|processed:boolean
let node = nodesData[k];
//potrebujem nody k danej linii //potrebujem nody k danej linii
if(record.line == nodesData[k].line) if(record.line == node.line)
{ {
let node = nodesData[k].node; let address = node.node;
let processed = nodesData[k].processed; console.log('^^^^ggggggg',address)
let processed = node.processed;
let dimming = node.dimming;
if(!node.profile)
{
console.log('+-+-+----llllll - posielam dimming')
let params = getParams(priorityTypes.high_priority);
//set dimming - LUM1_13 - 647 je node linie 1 kt. dobre vidime
params.type = "cmd";
params.tbname = node.tbname;
params.address = address;
params.register = 1;//dimming
params.recipient = 1;//slave
params.byte4 = dimming;
params.rw = 1;//write
params.timestamp = priorityTypes.high_priority;
params.info = 'setNodeDimming';
//params.debug = true;
tasks.push(params)
}
if(!processed) if(!processed)
{ {
processNodeProfile(node); console.log('=====procesujem profille')
processNodeProfile(address);
} }
else{ else
{
//logger.debug( `node ${node} profile for line ${nodesData[k].line} was already processed`); //logger.debug( `node ${node} profile for line ${nodesData[k].line} was already processed`);
} }
} }
@ -996,7 +1070,7 @@ exports.install = function(instance) {
logger.debug("linia", line, obj); logger.debug("linia", line, obj);
instance.send(instanceSendTo.dido_controller, obj); instance.send(instanceSendTo.di_do_controller, obj);
} }
function turnOffLine(line, info) function turnOffLine(line, info)
@ -1009,7 +1083,7 @@ exports.install = function(instance) {
logger.debug("linia", line, obj); logger.debug("linia", line, obj);
instance.send(instanceSendTo.dido_controller, obj); instance.send(instanceSendTo.di_do_controller, obj);
} }
function detectIfResponseIsValid(bytes) function detectIfResponseIsValid(bytes)
@ -1131,7 +1205,6 @@ exports.install = function(instance) {
let sunCalcResult = calculateDuskDown(new Date(), undefined, duskOffset, dawnOffset); let sunCalcResult = calculateDuskDown(new Date(), undefined, duskOffset, dawnOffset);
console.log(sunCalcResult); console.log(sunCalcResult);
monitor.info("--> dusk - dawn", sunCalcResult);
//if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo //if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo
//if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo //if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo
@ -1313,7 +1386,7 @@ exports.install = function(instance) {
let time_points = profile.time_points; let time_points = profile.time_points;
if(time_points == undefined) time_points = profile.intervals; if(time_points == undefined) time_points = profile.intervals;
//monitor.info("buildTasks: time_points", time_points); // monitor.info("buildTasks: time_points", time_points);
let currentValue = 0; let currentValue = 0;
if(time_points.length > 0) currentValue = time_points[ time_points.length - 1].value; if(time_points.length > 0) currentValue = time_points[ time_points.length - 1].value;
@ -1324,7 +1397,7 @@ exports.install = function(instance) {
//let now = new Date().toLocaleString("en-US", {timeZone: "Europe/Bratislava"}); //let now = new Date().toLocaleString("en-US", {timeZone: "Europe/Bratislava"});
let sunCalcResult = calculateDuskDown(new Date(), line); let sunCalcResult = calculateDuskDown(new Date(), line);
// monitor.info("dusk and dawn sunCalcResult", line, sunCalcResult); monitor.info("dusk and dawn sunCalcResult", line, sunCalcResult);
//add to timpoints //add to timpoints
if(profile.dawn_lux_sensor == false) time_points.push( {"start_time": sunCalcResult["dawn"], "value": 1, "isDawn": true} ); if(profile.dawn_lux_sensor == false) time_points.push( {"start_time": sunCalcResult["dawn"], "value": 1, "isDawn": true} );
@ -1507,8 +1580,7 @@ exports.install = function(instance) {
{ {
//run broadcast Time of dusk //run broadcast Time of dusk
// addMinutesToTimestamp = 60*5; addMinutesToTimestamp = 60*3;
addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk
let params = getParams(priorityTypes.node_broadcast); let params = getParams(priorityTypes.node_broadcast);
@ -1546,10 +1618,8 @@ exports.install = function(instance) {
} }
{ {
//run broadcast Time of dawn //run broadcast Time of dawn
// addMinutesToTimestamp = 60*5; addMinutesToTimestamp = 60*3;
addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn
let params = getParams(priorityTypes.node_broadcast); let params = getParams(priorityTypes.node_broadcast);
@ -1824,7 +1894,6 @@ exports.install = function(instance) {
{ {
let line = keys[i];//line is turned off by default let line = keys[i];//line is turned off by default
let profilestr = relaysData[line].profile; let profilestr = relaysData[line].profile;
let contactor = relaysData[line].contactor; // 0 or 1 - vypnuta/zapnuta
try{ try{
@ -1833,7 +1902,7 @@ exports.install = function(instance) {
if(profile.astro_clock == true) if(profile.astro_clock == true)
{ {
let sunCalcResult = calculateDuskDown(now, line); let sunCalcResult = calculateDuskDown(date, line);
//dawn: usvit/vychod - lux je nad hranicou - vypnem //dawn: usvit/vychod - lux je nad hranicou - vypnem
//dusk: zapad pod hranicou - zapnem //dusk: zapad pod hranicou - zapnem
@ -1842,13 +1911,10 @@ exports.install = function(instance) {
//"dusk_lux_sensor_time_window": 30, //"dusk_lux_sensor_time_window": 30,
//vychod //vychod
// LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
if(profile.dawn_lux_sensor == true) if(profile.dawn_lux_sensor == true)
{ {
let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); let lux_sensor_time_window1 = sunCalcResult.dawn_time - parseInt( profile.dawn_lux_sensor_time_window );
let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); let lux_sensor_time_window2 = sunCalcResult.dawn_time + parseInt( profile.dawn_lux_sensor_time_window );
//console.log('------>>>', new Date(lux_sensor_time_window1), new Date(lux_sensor_time_window2), lux_sensor_time_window1, lux_sensor_time_window2)
//console.log('++++-->>>', new Date(sunCalcResult.dusk_time), new Date(sunCalcResult.dawn_time))
if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2)
{ {
@ -1856,13 +1922,13 @@ exports.install = function(instance) {
if(lux_sensor_value > profile.dawn_lux_sensor_value) if(lux_sensor_value > profile.dawn_lux_sensor_value)
{ {
//vypnem //vypnem
if(contactor) turnOffLine(line, "profile: dawn - turnOff line according to lux sensor"); turnOffLine(line, "profile: dawn - turnOff line according to lux sensor");
}
else
{
//zapnem
turnOnLine(line, "profile: dawn - turnOn line according to lux sensor");
} }
// else
// {
// //zapnem
// if(!contactor) turnOnLine(line, "profile: dawn - turnOn line according to lux sensor");
// }
} }
@ -1877,8 +1943,8 @@ exports.install = function(instance) {
//zapad //zapad
if(profile.dusk_lux_sensor == true) 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_window1 = sunCalcResult.dusk_time - parseInt( profile.dusk_lux_sensor_time_window );
let lux_sensor_time_window2 = 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 );
if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2)
{ {
@ -1886,13 +1952,13 @@ exports.install = function(instance) {
if(lux_sensor_value < profile.dusk_lux_sensor_value) if(lux_sensor_value < profile.dusk_lux_sensor_value)
{ {
//zapnem //zapnem
if(!contactor) turnOnLine(line, "profile: dusk - turnOn line according to lux sensor"); turnOnLine(line, "profile: dusk - turnOff line according to lux sensor");
}
else
{
//vypnem
turnOffLine(line, "profile: dusk - turnOff line according to lux sensor");
} }
// else
// {
// //vypnem
// if(contactor) turnOffLine(line, "profile: dusk - turnOff line according to lux sensor");
// }
} }
} }
@ -1939,6 +2005,27 @@ exports.install = function(instance) {
} }
} }
async function updateNodeDimming(node, value) {
if(node == 0) return;
let nodeObj = nodesData[node];
console.log('-------nodeObjjjj', nodeObj);
if(nodeObj == undefined || value == undefined) return;
console.log('*-*-**-pppppp',nodeObj.dimming, value)
if(nodeObj.dimming !== value)
{
await dbNodes.modify({ dimming: value }).where("node", node).make(function(builder) {
builder.callback(function(err, response) {
if(err == null) nodesData[node].dimming = value;
console.log('+++//** NDffff',nodesData)
});
});
}
}
async function runTasks() { async function runTasks() {
@ -2124,8 +2211,6 @@ exports.install = function(instance) {
} }
} }
//kontrola nespracovanych profilov nodov //kontrola nespracovanych profilov nodov
if(type == "process_profiles") if(type == "process_profiles")
{ {
@ -2373,6 +2458,8 @@ exports.install = function(instance) {
//set dusk/down for broadcast //set dusk/down for broadcast
//Time of dusk //Time of dusk
if(params.register == 6 && params.recipient === 2) if(params.register == 6 && params.recipient === 2)
{ {
@ -2507,17 +2594,101 @@ exports.install = function(instance) {
} }
} }
// ak nastavujeme dimming z platformy, zapiseme ho do nodes.table. Ak sa spusta flow, a node nema profil, nacitame dimming z nodes.table
if(params.info == "setNodeDimming")
{
console.log('++++++eeeeeeeee',params)
console.log('*********aaaa',params.address, params.byte4);
updateNodeDimming(params.address, params.byte4);
}
//parse read response //parse read response
let values = {}; let values = {};
if(params.rw == 0) { if(params.rw == 0) {
values = processResponse(register, dataBytes);//read values = processResponse(register, dataBytes);//read
// console.log('-------****', values);
} }
if(params.rw == 1) if(params.rw == 1)
{ //write command {
//write command
//set command dimming //set command dimming
if(params.register == 1) values = {"comm_status": message};
if(params.register == 1)
{
values = {"comm_status": message};
} }
}
if(params.info == 'Dimming for CCT')
{
//Now we have node dimming value. We use it to set cct with following task (dimming value is byte 4):
let setCCT = getParams(priorityTypes.high_priority);
setCCT.type = "cmd";
setCCT.tbname = tbname;
setCCT.address = params.address;
setCCT.register = 1; //dimming
setCCT.recipient = 1; //slave
setCCT.byte1 = 1;
setCCT.byte2 = params.cct.byte2;
setCCT.byte3 = params.cct.byte3;
setCCT.byte4 = dataBytes[3] //dimming value + 128;
// setCCT.cct = params.cct.value; // we have cct value from platform call.
setCCT.rw = 1;//write
setCCT.timestamp = priorityTypes.high_priority;
setCCT.info = 'SetCCT';
setCCT.debug = true;
tasks.push(setCCT);
return;
}
if(params.info == 'dimming_no_mov')
{
//Now we have 4 bytes from 42 register. We leave first 3 bytes, and overwrite byte 4 with value from platform:
let setDNM = getParams(priorityTypes.high_priority);
setDNM.type = "cmd";
setDNM.tbname = tbname;
setDNM.address = params.address;
setDNM.register = 42; //dimming
setDNM.recipient = 1; //slave
setDNM.byte1 = 1;
setDNM.byte2 = dataBytes[1];
setDNM.byte3 = dataBytes[2];
setDNM.byte4 = params.value + 128;
setDNM.rw = 1;//write
setDNM.timestamp = priorityTypes.high_priority;
setDNM.info = 'setDNM';
setDNM.debug = true;
tasks.push(setDNM);
return;
}
if(params.info == "cct_no_mov")
{
//Now we have 4 bytes from register 42. We leave byte 0 and byte 4, and overwrite byte 2 and 3 with values from platform:
let setCCT = getParams(priorityTypes.high_priority);
setCCT.type = "cmd";
setCCT.tbname = tbname;
setCCT.address = params.address;
setCCT.register = 42; //dimming
setCCT.recipient = 1; //slave
setCCT.byte1 = 1;
setCCT.byte2 = params.cct.byte2;
setCCT.byte3 = params.cct.byte3;
setCCT.byte4 = dataBytes[3]; // should be byte4, that we got from register 42
setCCT.rw = 1;//write
setCCT.timestamp = priorityTypes.high_priority;
setCCT.info = 'setCCT';
setCCT.debug = true;
tasks.push(setCCT);
return;
}
if(params.register == 0) values["status"] = message; if(params.register == 0) values["status"] = message;
//fw version - register == 4 //fw version - register == 4
@ -2654,7 +2825,9 @@ exports.install = function(instance) {
delete cmdCounter[params.address]; delete cmdCounter[params.address];
let tbname = nodesData[ params.address ].tbname; let tbname = nodesData[ params.address ].tbname;
logger.debug( "profil nebol úspešne odoslaný na node č. ", params, result, resp);
//! LOG SPRACOVANIA PROFILU
//logger.debug( "profil nebol úspešne odoslaný na node č. ", params, result, resp);
//sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "profil nebol úspešne odoslaný na node č. " + params.address, "", instanceSendTo.tb, instance, null ); //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "profil nebol úspešne odoslaný na node č. " + params.address, "", instanceSendTo.tb, instance, null );
sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", instanceSendTo.tb, instance ); sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", instanceSendTo.tb, instance );
@ -2936,6 +3109,25 @@ exports.install = function(instance) {
rsPort.close(); rsPort.close();
}); });
// list of available node commands from platform
const rpcNodeCommands = ["dimming", "dimming_no_mov", "cct", "cct_no_mov", "timeout"];
//finds node, whose value needs to be modified from rpc platform call
function findNode(tbname)
{
let keys = Object.keys(nodesData);
let node = null;
for(let i = 0; i < keys.length; i++)
{
node = keys[i];
if(tbname == nodesData[node].tbname.trim()) return node;
}
return null;
}
//onData //onData
instance.on("data", async function(flowdata) { instance.on("data", async function(flowdata) {
//instance.on("data", (data) => { //instance.on("data", (data) => {
@ -2995,8 +3187,8 @@ exports.install = function(instance) {
//logger.debug("dido", flowdata.data); //logger.debug("dido", flowdata.data);
if(flowdata.data.hasOwnProperty("sender")) if(flowdata.data.hasOwnProperty("sender"))
{ {
//data from dido_controller //data from di_do_controller
if(flowdata.data.sender == "dido_controller") if(flowdata.data.sender == "di_do_controller")
{ {
if(flowdata.data.hasOwnProperty("cmd")) if(flowdata.data.hasOwnProperty("cmd"))
@ -3124,6 +3316,7 @@ exports.install = function(instance) {
return; return;
} }
//data from worksys //data from worksys
if(flowdata.data.hasOwnProperty("topic")) if(flowdata.data.hasOwnProperty("topic"))
{ {
@ -3142,7 +3335,8 @@ exports.install = function(instance) {
logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method); logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method);
logger.debug("----------------------------"); logger.debug("----------------------------");
if(entity_type == "street_luminaire") 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") if(method == "set_command")
{ {
@ -3150,21 +3344,28 @@ exports.install = function(instance) {
//let command = data.params.command; //let command = data.params.command;
let value = data.params.payload.value; let value = data.params.payload.value;
//we find node to set new value to from nodes.table
let node = null;
if(rpcNodeCommands.includes(command))
{
node = findNode(tbname);
if(!node)
{
logger.debug(`rpc set command - ${command} : unable to find tbname: ${tbname}`);
return;
}
}
else
{
instance.send(instanceSendTo.debug, "undefined command " + command);
logger.debug("undefined command", command);
return;
}
if(command == "dimming") 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.trim())
{
let params = getParams(priorityTypes.high_priority); let params = getParams(priorityTypes.high_priority);
value = parseInt(value); value = parseInt(value);
@ -3179,7 +3380,7 @@ exports.install = function(instance) {
params.byte4 = value; params.byte4 = value;
params.rw = 1;//write params.rw = 1;//write
params.timestamp = priorityTypes.high_priority; params.timestamp = priorityTypes.high_priority;
params.info = 'set dimming from platform'; params.info = 'setNodeDimming';
//params.debug = true; //params.debug = true;
//ak linia je //ak linia je
@ -3189,7 +3390,9 @@ exports.install = function(instance) {
tasks.push(params); tasks.push(params);
setTimeout(function(){ updateNodeDimming(node, value);
setTimeout(function() {
//spustime o 4 sekundy neskor, s prioritou priorityTypes.high_priority //spustime o 4 sekundy neskor, s prioritou priorityTypes.high_priority
//a pridame aj vyreportovanie dimmingu //a pridame aj vyreportovanie dimmingu
@ -3260,24 +3463,130 @@ exports.install = function(instance) {
tasks.push(params); tasks.push(params);
} }
},4000); },5000);
nodeWasFound = true;
break;
} }
} else if(command === "cct")
if(!nodeWasFound)
{ {
logger.debug("set dimming from platform", "unable to find tbname", tbname);
let params = getParams(priorityTypes.high_priority);
value = parseInt(value);
byte2 = Math.floor(value/256);
byte3 = value - (byte2 * 256);
// To set cct, we need to get node dimming first. We send this command. After we get dimming
// value from rsPort (in writeData function), we send command to set cct. Byte2 and 3 are cct
// byte4 is dimming (for example 100 or 50)
params.type = "cmd";
params.tbname = tbname;
params.address = node;
params.register = 1; //dimming
params.recipient = 1; //slave
params.rw = 0; //read
params.timestamp = priorityTypes.high_priority;
params.info = 'Dimming for CCT';
params.cct = {byte2: byte2, byte3: byte3, value: value};
params.debug = true;
console.log('-------- cct queued in tasks');
tasks.push(params);
} }
} else if(command == "timeout")
else
{ {
instance.send(instanceSendTo.debug, "undefined command " + command); let params = getParams(priorityTypes.high_priority);
logger.debug("undefined command", command);
value = parseInt(value);
byte3 = Math.floor(value/256);
byte4 = value - (byte3 * 256);
params.type = "cmd";
params.tbname = tbname;
params.address = node;
params.register = 104; //timeout
params.recipient = 1; //slave
params.rw = 1;//write
params.byte3 = byte3;
params.byte4 = byte4;
params.value = value;
params.timestamp = priorityTypes.high_priority;
params.info = 'SetNodeTimeout';
params.debug = true;
console.log('-------- SetNodeTimeout queued in tasks');
tasks.push(params);
setTimeout(function() {
// vyreportujeme nodeTimeoutMovement na platformu
let params = getParams(priorityTypes.high_priority);
params.type = "cmd";
params.tbname = tbname;
params.address = node;
params.register = 104;//dimming
params.recipient = 1;//slave
params.rw = 0;//read
params.timestamp = priorityTypes.high_priority;
params.info = 'ReadNodeTimeout';
params.debug = false;
tasks.push(params);
},5000);
}
else if(command == "dimming_no_mov")
{
let params = getParams(priorityTypes.high_priority);
value = parseInt(value);
// To set dimming_no_mov, we need to get node cct_no_mov first. We send this command. After we get cct
// value from rsPort (in writeData function), we send command to set dimming_no_mov. Byte2 and 3 are cct
// byte4 is dimming from platform (for example 100 or 50)
params.type = "cmd";
params.tbname = tbname;
params.address = node;
params.register = 42; //dimming
params.recipient = 1; //slave
params.rw = 0; //read
params.timestamp = priorityTypes.high_priority;
params.info = 'dimming_no_mov';
params.value = value;
params.debug = true;
console.log('-------- dimming_no_mov queued in tasks');
tasks.push(params);
}
else if(command == "cct_no_mov")
{
let params = getParams(priorityTypes.high_priority);
value = parseInt(value);
byte2 = Math.floor(value/256);
byte3 = value - (byte2 * 256);
// To set cct_no_mov, we need to get node dimming_no_mov first. We send this command. After we get dimming
// value from rsPort (in writeData function), we send command to set cct_no_mov. Byte2 and 3 are cct from platform
// byte4 is dimming (for example 100 or 50)
params.type = "cmd";
params.tbname = tbname;
params.address = node;
params.register = 42; //dimming_no_mov
params.recipient = 1; //slave
params.rw = 0; //read
params.timestamp = priorityTypes.high_priority;
params.info = "cct_no_mov";
params.cct = {byte2: byte2, byte3: byte3};
params.debug = true;
console.log('-------- cct_no_mov queued in tasks');
tasks.push(params);
} }
return; return;
@ -3297,7 +3606,29 @@ exports.install = function(instance) {
if(tbname == nodesData[node].tbname.trim()) if(tbname == nodesData[node].tbname.trim())
{ {
if(profile != "") profile = JSON.stringify(profile); if(profile == "")
{
// ak nie je profile, nastavime dimming svietidla podla nodes.table
let params = getParams(priorityTypes.high_priority);
params.type = "cmd";
params.tbname = tbname;
params.address = node;
params.register = 1;//dimming
params.recipient = 1;//slave
params.byte4 = nodesData[node].dimming;
params.rw = 1;//write
params.timestamp = priorityTypes.high_priority;
params.info = 'setNodeDimming';
//params.debug = true;
logger.debug("dimming", params);
tasks.push(params);
}
else
{
profile = JSON.stringify(profile);
}
dbNodes.modify({ processed: false, profile: profile }).where("node", node).make(function(builder) { dbNodes.modify({ processed: false, profile: profile }).where("node", node).make(function(builder) {
builder.callback(function(err, response) { builder.callback(function(err, response) {
@ -3332,7 +3663,7 @@ exports.install = function(instance) {
} }
//nastav profil linie z platformy //nastav profil linie z platformy
else if(entity_type == "edb_line" || entity_type == "edb" || entity_type == "edb_line_ver4" || entity_type == "edb_ver4_se") else if(entity_type == "edb_line" || entity_type == "edb"|| entity_type == "edb_line_ver4")
{ {
//profil linie //profil linie
//relays.table line:number|tbname:string|contactor:number|profile:string //relays.table line:number|tbname:string|contactor:number|profile:string
@ -3455,8 +3786,8 @@ exports.install = function(instance) {
} }
} }
}) })
} // end of exports.install = function(instance)
} // end of instance.export
/** /**
@ -3585,6 +3916,7 @@ setCorrectPlcTimeOnceADay();
///helper functions ///helper functions
function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0) function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0)
@ -3696,22 +4028,33 @@ function processResponse(register, bytes)
let brightness = 0; let brightness = 0;
let dimming = byte0; let dimming = byte0;
if(dimming > 128) { if(dimming > 128) {
//dimming = -128;
brightness = 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; values["dimming"] = brightness;
let cct;
if(byte3 == 1) cct = (byte2 * 256) + byte1;
//else cct = bytesToInt(bytes.slice(0, 3));
if(cct) values["cct"] = cct;
return values; return values;
} }
//Dimming_no_mov
if(register == 42)
{
values["dimming_no_mov"] = byte0 - 128;
let cct;
if(byte3 == 1) cct = (byte2 * 256) + byte1;
if(cct) values["cct_no_mov"] = cct;
return values;
}
// //
if(register == 4) if(register == 4)
{ {
@ -3905,6 +4248,17 @@ function processResponse(register, bytes)
values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")"; values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
} }
if(register == 95)
{
values["lux_level"] = (byte1 * 256) + byte0;
}
if(register == 104)
{
values["movement_timeout"] = (byte1 * 256) + byte0;
values["movement_state"] = byte2;
}
return values; return values;
} }
@ -3981,3 +4335,76 @@ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4
// Node profile rpc
// {
// "topic": "v1/gateway/rpc",
// "content": {
// "device": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV",
// "data": {
// "id": 53,
// "method": "set_profile",
// "params": {
// "entities": [
// {
// "entity_type": "street_luminaire",
// "tb_name": "LpkVlmq4b3jMwJQxBZ8akayrXAP6o97Ke0aOYEg2"
// }
// ],
// "payload": {
// "intervals": [
// {
// "cct": 3000,
// "value": 0,
// "end_time": "17:50",
// "start_time": "13:00"
// },
// {
// "cct": 3000,
// "value": 100,
// "end_time": "21:30",
// "start_time": "17:50"
// },
// {
// "cct": 3000,
// "value": 0,
// "end_time": "13:00",
// "start_time": "07:10"
// },
// {
// "cct": 3000,
// "value": 50,
// "end_time": "00:00",
// "start_time": "21:30"
// },
// {
// "cct": 3000,
// "value": 10,
// "end_time": "04:30",
// "start_time": "00:00"
// },
// {
// "cct": 3000,
// "value": 100,
// "end_time": "07:10",
// "start_time": "04:30"
// }
// ],
// "astro_clock": true,
// "dawn_lux_sensor": false,
// "dusk_lux_sensor": false,
// "dawn_lux_sensor_value": 5,
// "dusk_lux_sensor_value": 5,
// "dawn_astro_clock_offset": 30,
// "dusk_astro_clock_offset": 20,
// "dawn_lux_sensor_time_window": 30,
// "dusk_lux_sensor_time_window": 30,
// "dawn_astro_clock_time_window": 60,
// "dusk_astro_clock_time_window": 60
// }
// }
// }
// }
// }

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
exports.id = 'dido_controller'; exports.id = 'di_do_controller';
exports.title = 'DIDO_Controller'; exports.title = 'DI_DO_Controller';
exports.version = '2.0.0'; exports.version = '1.0.0';
exports.group = 'Worksys'; exports.group = 'Worksys';
exports.color = '#2134B0'; exports.color = '#2134B0';
exports.input = 3; exports.input = 1;
exports.output = ["red", "white", "yellow"]; exports.output = ["red", "white", "yellow"];
exports.click = false; exports.click = false;
exports.author = 'Daniel Segeš'; exports.author = 'Daniel Segeš';
@ -60,7 +60,7 @@ state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda
//globals //globals
//FIRMWARE version //FIRMWARE version
FLOW.OMS_edge_fw_version = "2023-10-18";//rok-mesiac-den FLOW.OMS_edge_fw_version = "2022-05-12";//rok-mesiac-den
FLOW.OMS_edgeName = ""; FLOW.OMS_edgeName = "";
FLOW.OMS_maintenance_mode = false; FLOW.OMS_maintenance_mode = false;
@ -178,7 +178,7 @@ exports.install = function(instance) {
deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič
deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód
deviceStatuses["door_condition"] = "closed";//Dverový kontakt deviceStatuses["door_condition"] = "closed";//Dverový kontakt
deviceStatuses["em"] = "OK";//elektromer rvo deviceStatuses["rvo"] = {status: "OK"};//elektromer rvo
deviceStatuses["temperature"] = "OK";//templomer deviceStatuses["temperature"] = "OK";//templomer
deviceStatuses["battery"] = "OK";//Batéria deviceStatuses["battery"] = "OK";//Batéria
deviceStatuses["power_supply"] = "OK";//Zdroj deviceStatuses["power_supply"] = "OK";//Zdroj
@ -187,7 +187,6 @@ exports.install = function(instance) {
deviceStatuses["state_of_breaker"] = {};//"Off";//Istič deviceStatuses["state_of_breaker"] = {};//"Off";//Istič
deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač
deviceStatuses["twilight_sensor"] = "OK"; //lux sensor
/* /*
dbRelays.on('change', function(doc, old) { dbRelays.on('change', function(doc, old) {
@ -303,7 +302,7 @@ exports.install = function(instance) {
let time = 3*1000; let time = 3*1000;
setTimeout(function(){ setTimeout(function(){
instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"}); instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "buildTasks"});
sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", instanceSendTo.tb, instance ); sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", instanceSendTo.tb, instance );
monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version); monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version);
@ -312,20 +311,6 @@ exports.install = function(instance) {
} }
// we ensure, all tasks will be rebuild every day at 11. To set correct switch off and on times
let sendRebuildTasksAt11 = null;
const checkIf11Oclock = () =>
{
const d = new Date();
const h = d.getHours();
if(h === 11)
{
instance.send(instanceSendTo.cmd_manager, {sender:"dido_controller", cmd:"buildTasks"});
}
}
sendRebuildTasksAt11 = setInterval(checkIf11Oclock, 3600000);
function handleRsPort() function handleRsPort()
{ {
//TODO build according to pins!!! //TODO build according to pins!!!
@ -463,6 +448,7 @@ exports.install = function(instance) {
// dev: 'input', // dev: 'input',
// mode: 'Simple' // mode: 'Simple'
// }, // },
ws.onmessage = function(data) { ws.onmessage = function(data) {
data = JSON.parse(data.data); data = JSON.parse(data.data);
@ -533,7 +519,6 @@ exports.install = function(instance) {
instance.on("close", () => { instance.on("close", () => {
if(rsPort) rsPort.close(); if(rsPort) rsPort.close();
if(ws) ws.close(); if(ws) ws.close();
clearInterval(sendRebuildTasksAt11);
}) })
loadAllDb(); loadAllDb();
@ -732,7 +717,7 @@ exports.install = function(instance) {
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1}; let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1};
ws.send(JSON.stringify(cmd)); ws.send(JSON.stringify(cmd));
//switchLogic(pin, 1) switchLogic(pin, 1)
} }
} }
@ -806,74 +791,51 @@ exports.install = function(instance) {
else if(ws) else if(ws)
{ {
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
//monitor.info("turnOffLine pin (relay)", pin); // monitor.info("turnOffLine pin (relay)", pin);
let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0}; let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0};
ws.send(JSON.stringify(cmd)); ws.send(JSON.stringify(cmd));
//switchLogic(pin, 0) switchLogic(pin, 0)
} }
} }
//data from modbus_reader or temperature sensor or twilight sensor or other modbus device
instance.on("0", flowdata => {
if(!flowdata.data instanceof Object) return;
// console.log('***********************', flowdata.data)
instance.send(instanceSendTo.debug, flowdata.data);
// we handle nok status from modbus_reader component and thermometer
if(flowdata.data?.status)
{
const status = flowdata.data.status;
if(status == "NOK-twilight_sensor")
{
deviceStatuses["twilight_sensor"] = "NOK";
}
else if(status == "NOK-em340" || status == "NOK-em111")
{
deviceStatuses["em"] = "NOK";
}
else if(status == "NOK-thermometer")
{
deviceStatuses["temperature"] = "NOK";
}
return;
}
const values = flowdata.data.values;
if(values.hasOwnProperty("twilight_sensor"))
{
instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"]});
deviceStatuses["twilight_sensor"] = "OK"
}
else if(values.hasOwnProperty("temperature"))
{
deviceStatuses["temperature"] = "OK";
}
// EM
else if(values.hasOwnProperty("total_power") || values.hasOwnProperty("total_energy") || values.hasOwnProperty("power_factor") || values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_1_current"))
{
deviceStatuses["em"] = "OK";
}
const updateStatus = checkFinalRVOStatus();
if(updateStatus) values.status = "OK";
sendTelemetry(values, FLOW.OMS_rvo_tbname);
})
// we expect array as flowdata.data // we expect array as flowdata.data
instance.on("1", flowdata => { instance.on("data", (flowdata) => {
console.log(flowdata.data); console.log(flowdata.data);
if(!flowdata.data instanceof Object) return; if(flowdata.data instanceof Object)
{
if(flowdata.data.hasOwnProperty("sender"))
{
//console.log("sender", flowdata.data);
if(flowdata.data.sender == "gettemperature")
{
deviceStatuses["temperature"] = flowdata.data.status;
}
else if(flowdata.data.sender == "modbus_citysys")
{
//elektromer rvo
if(flowdata.data.tbdata.hasOwnProperty(edgeName))
{
//rvo
deviceStatuses["rvo"] = {status: flowdata.data.tbdata[edgeName][0]["values"]["status"], tbdata: flowdata.data.tbdata};
}
else if(flowdata.data.tbdata.hasOwnProperty("twilight_sensor"))
{
switchLogic('twilight_sensor', flowdata.data.tbdata["twilight_sensor"])
}
}
instance.send(instanceSendTo.debug, flowdata.data );
return;
}
let obj = flowdata.data; let obj = flowdata.data;
let line = obj.line; let line = obj.line;
let force = obj.force; let force = obj.force;
let info = obj.info; let info = obj.info;
@ -883,15 +845,17 @@ exports.install = function(instance) {
else if(obj.command == "turnOnAlarm") turnOnAlarm(); else if(obj.command == "turnOnAlarm") turnOnAlarm();
else if(obj.command == "turnOffAlarm") turnOffAlarm(); else if(obj.command == "turnOffAlarm") turnOffAlarm();
return;
}
//! ake data prichadzaju z cmd_manager.js ??? //! ake data prichadzaju z cmd_manager.js ???
//TODO transform to websocket //TODO transform to websocket
if (Array.isArray(obj)){ if (Array.isArray(flowdata.data)){
rsPort.write(Buffer.from(obj), function(err) { rsPort.write(Buffer.from(flowdata.data), function(err) {
switchLogic(obj); switchLogic(flowdata.data);
instance.send(instanceSendTo.debug, {"WRITE":obj} ); instance.send(instanceSendTo.debug, {"WRITE":flowdata.data} );
}); });
} }
}) })
@ -903,17 +867,12 @@ exports.install = function(instance) {
let bytes = []; let bytes = [];
let bits = []; let bits = [];
//Hlavný istič - state_of_main_switch
if(deviceStatuses["state_of_main_switch"] == "On")
{
bits.push(0);
}
else if(deviceStatuses["state_of_main_switch"] == "Off")
{
bits.push(1);
}
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY //Hlavný istič - state_of_main_switch
if(deviceStatuses["state_of_main_switch"] == "On") bits.push(0);
else if(deviceStatuses["state_of_main_switch"] == "Off") bits.push(1);
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false
if(!FLOW.OMS_maintenance_mode) if(!FLOW.OMS_maintenance_mode)
{ {
if(deviceStatuses["rotary_switch_state"] == "Manual") if(deviceStatuses["rotary_switch_state"] == "Manual")
@ -944,88 +903,41 @@ exports.install = function(instance) {
{ {
bits.push(0); bits.push(0);
} }
else else bits.push(1);
{
bits.push(1);
}
//EM //EM
if(deviceStatuses["em"] == "NOK") if(deviceStatuses["rvo"].status == "NOK") bits.push(1);
{ else bits.push(0);
bits.push(1);
}
else
{
bits.push(0);
}
//Teplomer //Teplomer
if(deviceStatuses["temperature"] == "NOK") if(deviceStatuses["temperature"] == "NOK") bits.push(1);
{ else bits.push(0);
bits.push(1);
}
else
{
bits.push(0);
}
//Batéria //Batéria
if(deviceStatuses["battery"] == "NOK") if(deviceStatuses["battery"] == "NOK") bits.push(1);
{ else bits.push(0);
bits.push(1);
}
else
{
bits.push(0);
}
//Zdroj //Zdroj
if(deviceStatuses["power_supply"] == "NOK") if(deviceStatuses["power_supply"] == "NOK") bits.push(1);
{ else bits.push(0);
bits.push(1);
}
else
{
bits.push(0);
}
//MN //MN
if(deviceStatuses["master_node"] == "NOK") if(deviceStatuses["master_node"] == "NOK") bits.push(1);
{ else bits.push(0);
bits.push(1);
}
else
{
bits.push(0);
}
//výpadok napätia na fáze //výpadok napätia na fáze
if(deviceStatuses["no_voltage"] == "NOK") if(deviceStatuses["no_voltage"] == "NOK") bits.push(1);
{ else bits.push(0);
bits.push(1);
}
else
{
bits.push(0);
}
if(deviceStatuses["twilight_sensor"] == "NOK")
{
bits.push(1);
}
else
{
bits.push(0); bits.push(0);
}
// doplnime do 16 bitov (2 byty)
for(let i = bits.length; i < 16; i++)
{
bits.push(0); bits.push(0);
} bits.push(0);
bits.push(0);
bits.push(0);
bits.push(0);
// console.log("calculateStateCode - deviceStatuses", deviceStatuses); //console.log("calculateStateCode - deviceStatuses", deviceStatuses);
// console.log("calculateStateCode", bits); //console.log("calculateStateCode", bits);
let byte0 = bitwise.byte.write(bits.slice(0,8).reverse()); let byte0 = bitwise.byte.write(bits.slice(0,8).reverse());
let byte1 = bitwise.byte.write(bits.slice(8).reverse()); let byte1 = bitwise.byte.write(bits.slice(8).reverse());
@ -1047,18 +959,10 @@ exports.install = function(instance) {
let status = "OK"; let status = "OK";
if(deviceStatuses["em"] == "NOK") if(deviceStatuses["rvo"].status == "NOK")
{ {
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: EM status is NOK"); let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: rvo status is NOK");
if(writeToFile) errLogger.error("checkFinalRVOStatus: EM status is NOK"); if(writeToFile) errLogger.error("checkFinalRVOStatus: rvo status is NOK", deviceStatuses["rvo"].tbdata);
status = "NOK";
}
if(deviceStatuses["twilight_sensor"] == "NOK")
{
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: twilight_sensor is NOK");
if(writeToFile) errLogger.error("checkFinalRVOStatus: twilight sensor is NOK");
status = "NOK"; status = "NOK";
} }
@ -1075,15 +979,10 @@ exports.install = function(instance) {
if(status == "OK") if(status == "OK")
{ {
let pinIndexes = [1, 4, 6]; for (const pinIndex of [1, 4, 6]) {
if(controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05'];
//console.log('-------- previousValues', previousValues);
for (const pinIndex of pinIndexes) {
if (previousValues[pinIndex] === 0) { if (previousValues[pinIndex] === 0) {
if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && FLOW.OMS_maintenance_mode) continue; if (pinIndex === 6 && FLOW.OMS_maintenance_mode) continue;
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0"); let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0");
if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type); if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type);
@ -1095,7 +994,7 @@ exports.install = function(instance) {
} }
} }
// battery status. If value is 1 - battery is NOK // battery status. If value is 1 - battery is not ok
if (previousValues[5] === 1) if (previousValues[5] === 1)
{ {
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery"); let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery");
@ -1104,6 +1003,18 @@ exports.install = function(instance) {
status = "NOK"; status = "NOK";
} }
//ak mame telemetriu z elektromeru, posleme
if(deviceStatuses["rvo"].tbdata != undefined)
{
//deviceStatuses["rvo"] = {status: flowdata.data.tbdata[edgeName][0]["values"]["status"], tbdata: flowdata.data.tbdata};
deviceStatuses["rvo"].tbdata[edgeName][0]["values"]["status"] = status;
instance.send(instanceSendTo.tb, deviceStatuses["rvo"].tbdata);
delete deviceStatuses["rvo"].tbdata;
}
//console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding); //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding);
if(!FLOW.OMS_masterNodeIsResponding) if(!FLOW.OMS_masterNodeIsResponding)
@ -1130,7 +1041,17 @@ exports.install = function(instance) {
if(status == "NOK") if(status == "NOK")
{ {
sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname);
const dataToTb = {
[edgeName]: [
{
"ts": Date.now(),
"values": {status: "NOK"}
}
]
}
instance.send(instanceSendTo.tb, dataToTb);
return false; return false;
} }
@ -1139,8 +1060,8 @@ exports.install = function(instance) {
} }
// we pass array to function in case of rsPort ==> switchLogic([55,3,0,1]) ==> [[55,3,0,1]] // we pass array to function in case of rsPort ==> switchLogic([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("relay1_03",1)
const switchLogic = (...args) => { const switchLogic = (...args) => {
let values = {status: "OK"}; let values = {status: "OK"};
@ -1174,27 +1095,28 @@ exports.install = function(instance) {
let tbname = obj.tbname; let tbname = obj.tbname;
//default value //default value
let value = "On"; let value = "Off";
if(newPinValue === 0) value = "Off"; if(newPinValue === 1) value = "On";
//Hlavný istič //Hlavný istič
//! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri if(type === "state_of_main_switch")
//! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition'
if(type === "!!!state_of_main_switch")
{ {
if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{ {
sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", instanceSendTo.tb, instance , "state_of_main_switch");
values["status"] = "NOK"; values["status"] = "NOK";
value = "Off";
deviceStatuses["state_of_main_switch"] = "Off";
} }
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{ {
sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", instanceSendTo.tb, instance , "state_of_main_switch");
value = "On";
deviceStatuses["state_of_main_switch"] = "On";
} }
deviceStatuses["state_of_main_switch"] = value;
} }
//Prevádzkový mód //Prevádzkový mód
@ -1226,9 +1148,9 @@ exports.install = function(instance) {
} }
//console.log('***********************', pin2, pin3) //console.log('***********************', pin2, pin3)
if (pin2 == 1 && pin3 == 0) value = "Manual"; if (pin2 == 0 && pin3 == 1) value = "Manual";
if (pin2 == 0 && pin3 == 0) value = "Off"; if (pin2 == 0 && pin3 == 0) value = "Off";
if (pin2 == 0 && pin3 == 1) value = "Automatic"; if (pin2 == 1 && pin3 == 0) value = "Automatic";
deviceStatuses["rotary_switch_state"] = value; deviceStatuses["rotary_switch_state"] = value;
@ -1236,14 +1158,14 @@ exports.install = function(instance) {
//ak je spracovany, a automatic - tak ho zapnem //ak je spracovany, a automatic - tak ho zapnem
//ak nie je spracovany, iba profil zapisem //ak nie je spracovany, iba profil zapisem
instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value}); instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "rotary_switch_state", value: value});
//console.log("rotary_switch_state pin", pin2, pin3, value); //console.log("rotary_switch_state pin", pin2, pin3, value);
} }
//Zdroj - pin 4 //Zdroj - pin 4
else if (type === "power_supply") else if (type === "power_supply")
{ {
if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", instanceSendTo.tb, instance); //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", instanceSendTo.tb, instance);
sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", instanceSendTo.tb, instance, "power_supply"); sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", instanceSendTo.tb, instance, "power_supply");
@ -1251,7 +1173,7 @@ exports.install = function(instance) {
deviceStatuses["power_supply"] = "NOK"; deviceStatuses["power_supply"] = "NOK";
} }
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", instanceSendTo.tb, instance); //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", instanceSendTo.tb, instance);
sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", instanceSendTo.tb, instance, "power_supply"); sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", instanceSendTo.tb, instance, "power_supply");
@ -1262,7 +1184,7 @@ exports.install = function(instance) {
//Batéria - pin 5 //Batéria - pin 5
else if (type === "battery") else if (type === "battery")
{ {
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", instanceSendTo.tb, instance); //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", instanceSendTo.tb, instance);
sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", instanceSendTo.tb, instance, "battery_level"); sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", instanceSendTo.tb, instance, "battery_level");
@ -1270,7 +1192,7 @@ exports.install = function(instance) {
deviceStatuses["battery"] = "NOK"; deviceStatuses["battery"] = "NOK";
} }
else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", instanceSendTo.tb, instance); //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", instanceSendTo.tb, instance);
sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", instanceSendTo.tb, instance, "battery_level"); sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", instanceSendTo.tb, instance, "battery_level");
@ -1279,11 +1201,9 @@ exports.install = function(instance) {
} }
} }
//Dverový kontakt - pin 6 //Dverový kontakt - pin 6
//! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch" else if(type == "door_condition")
//! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition'
else if(type == "door_condition" || type === "state_of_main_switch")
{ {
newPinValue === 0 ? value = "open" : value = "closed"; newPinValue === 0 ? value = "closed" : value = "open";
if (newPinValue != previousValues[pinIndex]) if (newPinValue != previousValues[pinIndex])
{ {
@ -1304,9 +1224,8 @@ exports.install = function(instance) {
//console.log(door_has_been_open_without_permision_alarm_is_on); //console.log(door_has_been_open_without_permision_alarm_is_on);
// zapneme sirenu //zapneme sirenu
// ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition") turnOnAlarm();
if(type === "door_condition") turnOnAlarm();
} }
if (value === "closed") if (value === "closed")
@ -1376,7 +1295,7 @@ exports.install = function(instance) {
if(diff >= twilight_sensor_interval * 60 * 1000) if(diff >= twilight_sensor_interval * 60 * 1000)
{ {
const average = twilight_sensor.reduce((acc, c) => acc + c.value, 0) / twilight_sensor.length; const average = twilight_sensor.reduce((acc, c) => acc + c.value, 0) / twilight_sensor.length;
instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: average}); instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "lux_sensor", value: average});
twilight_sensor = []; twilight_sensor = [];
@ -1384,19 +1303,17 @@ exports.install = function(instance) {
} }
//else console.log("lux_sensor", value, diff); //else console.log("lux_sensor", value, diff);
} }
else
{
instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "lux_sensor", value: value});
}
} }
else if(type == "state_of_contactor") else if(type == "state_of_contactor")
{ {
//sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", instanceSendTo.tb, instance ); //sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", instanceSendTo.tb, instance );
if(!(deviceStatuses["state_of_contactor"][line] == value))
{
sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", instanceSendTo.tb, instance ); sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", instanceSendTo.tb, instance );
}
else
{
deviceStatuses["state_of_contactor"][line] = value; deviceStatuses["state_of_contactor"][line] = value;
}
//true, false //true, false
if(value === "On") value = true; if(value === "On") value = true;
@ -1433,7 +1350,7 @@ exports.install = function(instance) {
//a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
setTimeout(function(){ setTimeout(function(){
instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged});
}, time); }, time);
reportLineStatus(line); reportLineStatus(line);
@ -1458,24 +1375,7 @@ exports.install = function(instance) {
if(valueChanged) if(valueChanged)
{ {
instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line}); instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "state_of_breaker", value: value, line: line});
//mame 3 istice. ked je viac ako 3 linie, dalsie sa zapajaju paralelne. to znamena na istici 1 je linia 1 a 4, na istici 2 je linia 2 a 5, na istici 3 je linia 3 a 6 (key je string ("4"))
//vyreportujeme a ohandlujeme liniu na tom istom istici ako paralelna linia
const lineOnSameBraker = line + 3 + "";
if(relaysData.hasOwnProperty(lineOnSameBraker)) {
instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "state_of_breaker", value: value, line: line + 3});
deviceStatuses["state_of_breaker"][line + 3] = value;
reportLineStatus(line + 3);
values[type] = value;
tbname = relaysData[lineOnSameBraker].tbname;
sendTelemetry(values, tbname);
delete values[type];
}
} }
if(value == "Off") values["status"] = "NOK"; if(value == "Off") values["status"] = "NOK";
@ -1483,28 +1383,26 @@ exports.install = function(instance) {
deviceStatuses["state_of_breaker"][line] = value; deviceStatuses["state_of_breaker"][line] = value;
reportLineStatus(line); reportLineStatus(line);
} }
values[type] = value; values[type] = value;
//if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode();
if(pinsData.hasOwnProperty(pinIndex))
{
let valueChanged = false;
if(newPinValue != previousValues[pinIndex])
{
valueChanged = true;
//pin was changed
previousValues[pinIndex] = newPinValue;
}
let result = checkFinalRVOStatus(); let result = checkFinalRVOStatus();
if(!result && line == 0) if(!result && line == 0)
{ {
values["status"] = "NOK"; values["status"] = "NOK";
} }
//--
//if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode();
if(pinsData.hasOwnProperty(pinIndex))
{
let valueChanged = false;
if(newPinValue != previousValues[pinIndex]) valueChanged = true;
if(type == "state_of_contactor") valueChanged = true; if(type == "state_of_contactor") valueChanged = true;
if(type == "rotary_switch_state") valueChanged = true; if(type == "rotary_switch_state") valueChanged = true;
if(type === "state_of_breaker") if(type === "state_of_breaker")
@ -1523,6 +1421,7 @@ exports.install = function(instance) {
//console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname); //console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname);
} }
if(valueChanged) if(valueChanged)
{ {
sendTelemetry(values, tbname); sendTelemetry(values, tbname);
@ -1544,6 +1443,10 @@ exports.install = function(instance) {
logger.debug("no pinIndex", pinsData[pinIndex], pinsData); logger.debug("no pinIndex", pinsData[pinIndex], pinsData);
} }
//pin was changed
previousValues[pinIndex] = newPinValue;
} }
@ -1889,24 +1792,3 @@ exports.install = function(instance) {
// {
// "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV": [
// {
// "ts": 1700409326353,
// "values": {
// "_event": {
// "type": "notice",
// "status": "new",
// "source": {
// "func": "rsPort.open()",
// "component": "1700343402190",
// "component_name": "DIDO_Controller",
// "edge": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV"
// },
// "message": "al_shariff_10.0.0.38: FLOW has been started ",
// "message_data": ""
// }
// }
// }
// ]
// }

View file

@ -1,18 +1,18 @@
exports.id = 'thermometer'; exports.id = 'gettemperature';
exports.title = 'Thermometer'; exports.title = 'Thermometer';
exports.group = 'Worksys'; exports.group = 'Worksys';
exports.color = '#5CB36D'; exports.color = '#5CB36D';
exports.version = '1.0.3'; exports.version = '1.0.2';
exports.output = ["red", "white", "blue"]; exports.output = ["red", "white", "blue"];
exports.author = 'Rastislav Kovac'; exports.author = 'Rastislav Kovac';
exports.icon = 'thermometer-three-quarters'; exports.icon = 'thermometer-three-quarters';
exports.readme = `# Getting temperature values for RVO. In case of LM, you need device address. In case of unipi, evok sends values, in case thermometer is installed`; exports.readme = `# Getting temperature values from RVO`;
const instanceSendTo = { const instanceSendTo = {
debug: 0, debug: 0,
tb: 1, tb: 1,
dido_controller: 2 di_do_controller: 2
} }
//read temperature - frequency //read temperature - frequency
@ -43,7 +43,7 @@ const monitor = log4js.getLogger("monitorLogs");
//monitor.info('info'); //monitor.info('info');
//errLogger.error("some error"); //errLogger.error("some error");
const { promisifyBuilder } = require('./helper/db_helper'); const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
const dbSettings = TABLE("settings"); const dbSettings = TABLE("settings");
let temperatureAddress = ""; let temperatureAddress = "";
@ -60,7 +60,7 @@ loadSettings();
exports.install = function(instance) { exports.install = function(instance) {
const { exec } = require('child_process'); const { exec } = require('child_process');
const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter'); const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js');
let startRead; let startRead;
let dataToTb; let dataToTb;
@ -76,9 +76,9 @@ exports.install = function(instance) {
}) })
const start = function() { const start = function(){
try { try{
if(FLOW.OMS_controller_type === "unipi") if(FLOW.OMS_controller_type === "unipi")
{ {
@ -130,8 +130,8 @@ exports.install = function(instance) {
monitor.info("Thermometer is not responding", error, FLOW.OMS_brokerready); monitor.info("Thermometer is not responding", error, FLOW.OMS_brokerready);
// instance.send(instanceSendTo.tb, dataToTb); // poslat stav nok do tb, ak to handluje dido_controller ?? instance.send(instanceSendTo.tb, dataToTb);
instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"}); instance.send(instanceSendTo.di_do_controller, {sender: "gettemperature", status: status});
} }
else parseData(stdout); else parseData(stdout);
} }
@ -162,9 +162,10 @@ exports.install = function(instance) {
logger.debug("gettemperature", data); logger.debug("gettemperature", data);
if(!isNaN(data)) { if (!isNaN(data)){
if(counter > 290)
//if ( counter > 290 )
{ {
instance.send(instanceSendTo.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break"); instance.send(instanceSendTo.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break");
@ -173,22 +174,21 @@ exports.install = function(instance) {
} }
logger.debug("gettemperature", data); logger.debug("gettemperature", data);
const values = {
"temperature": Number(data.toFixed(2)),
"status": "OK"
}
dataToTb = { dataToTb = {
[edgeName]: [ [edgeName]: [
{ {
"ts": Date.now(), "ts": Date.now(),
"values":values "values": {
"temperature": Number(data.toFixed(2)),
"status": "OK"
}
} }
] ]
} }
instance.send(instanceSendTo.tb, dataToTb); instance.send(instanceSendTo.tb, dataToTb);
instance.send(instanceSendTo.dido_controller, values); instance.send(instanceSendTo.di_do_controller, {sender: "gettemperature", status: "OK"});
counter = 0; counter = 0;
@ -204,8 +204,9 @@ exports.install = function(instance) {
sendNotification("parseData", edgeName, "thermometer_sends_invalid_data", {}, "", instanceSendTo.tb, instance, "thermometer"); sendNotification("parseData", edgeName, "thermometer_sends_invalid_data", {}, "", instanceSendTo.tb, instance, "thermometer");
instance.send(instanceSendTo.debug, "[Get temperature component] - no temperature data from RVO for more than 1 day"); instance.send(instanceSendTo.debug, "[Get temperature component] - no temperature data from RVO for more than 1 day");
instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"}); instance.send(instanceSendTo.di_do_controller, {sender: "gettemperature", status: "NOK"});
} }
} }
} }
@ -215,4 +216,5 @@ exports.install = function(instance) {
}, 3000); }, 3000);
startRead = setInterval(start, timeoutMin * 1000 * 60); startRead = setInterval(start, timeoutMin * 1000 * 60);
}; };

1135
flow/modbus_citysys.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,336 +0,0 @@
exports.id = 'modbus_reader';
exports.title = 'Modbus reader';
exports.version = '2.0.0';
exports.group = 'Worksys';
exports.color = '#2134B0';
exports.output = ["red", "white"];
exports.click = false;
exports.author = 'Rastislav Kovac';
exports.icon = 'bolt';
exports.readme = `
Modbus requests to modbus devices (electromer, twilight sensor, thermometer.
Component keeps running arround deviceConfig array in "timeoutInterval" intervals. Array items are objects with single modbus devices.
Everything is sent to dido_controller. If requests to device fail (all registers must fail to send NOK status) , we send "NOK-'device'" status to dido_controller.
This device needs to be configured in dido_controller!!! Double check if it is. In dido_controller we calculate final status and all values with status are pushed to tb.
`;
const modbus = require('jsmodbus')
const SerialPort = require('serialport')
const { timeoutInterval, deviceConfig } = require("../databases/modbus_config");
const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
const errorHandler = new ErrorToServiceHandler();
const { sendNotification } = require('./helper/notification_reporter');
const instanceSendTo = {
debug: 0,
dido_controller: 1,
};
//to handle NOK and OK sendNotifications s
const numberOfNotResponding = {};
let tbName = null;
exports.install = function(instance) {
class SocketWithClients {
constructor () {
this.stream = null;
this.socket = null;
this.clients = {};
this.allValues = {};
this.errors = 0;
this.index = 0;
this.timeoutInterval = 5000;
// kedze potrebujeme ist stale dookola pre jednotlive zariadenia, potrebujeme ci uz index ako aj adresu zariadenia, a aj pocet registrov na vycitanie
this.deviceAddress = null; // adresa zariadenia (1 ma EM340 a 2 ma twilight_sensor)
this.indexInDeviceConfig = 0; // prvy item v deviceConfig
this.lengthOfActualDeviceStream = null;
this.device = null;
this.startSocket();
}
startSocket = () => {
let obj = this;
this.socket = new SerialPort("/dev/ttymxc0", {
baudRate: 9600,
})
// we create a client for every deviceAddress ( = address) in list and push them into dictionary
for( let i = 0; i < deviceConfig.length; i++)
{
this.clients[deviceConfig[i].deviceAddress] = new modbus.client.RTU(this.socket, deviceConfig[i].deviceAddress);
}
this.socket.on('error', function(e) {
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('Socket connection closed ' + exports.title + ' Waiting 10 seconds before trying to connect again');
setTimeout(obj.startSocket, 10000);
});
this.socket.on('open', function () {
console.log("socket connected");
obj.getActualStreamAndDevice();
obj.timeoutInterval = timeoutInterval;
})
};
getActualStreamAndDevice = () => {
const dev = deviceConfig[this.indexInDeviceConfig];
this.index = 0;
this.errors = 0;
this.stream = dev.stream;
this.lengthOfActualDeviceStream = dev.stream.length;
this.deviceAddress = dev.deviceAddress; // 1 or 2 or any number
this.device = dev.device; //em340, twilight_sensor
if(this.indexInDeviceConfig == 0) setTimeout(this.readRegisters, this.timeoutInterval);
else setTimeout(this.readRegisters, 2000);
}
readRegisters = () => {
const str = this.stream[this.index];
const register = str.register;
const size = str.size;
const tbAttribute = str.tbAttribute;
let obj = this;
this.clients[this.deviceAddress].readHoldingRegisters(register, size)
.then( function (resp) {
resp = resp.response._body.valuesAsArray; //resp is array of length 1 or 2, f.e. [2360,0]
// console.log(deviceAddress, register, tbAttribute, resp);
//device is responding again after NOK status
if(numberOfNotResponding.hasOwnProperty(obj.device))
{
let message = "";
if(obj.device == "em340")
{
message = "electrometer_ok";
}
else if(obj.device == "twilight_sensor")
{
message = "twilight_sensor_ok";
}
message && sendNotification("modbus_reader: readRegisters", tbName, message, {}, "", instanceSendTo.tb, instance);
delete numberOfNotResponding[obj.device];
}
obj.transformResponse(resp, register, obj.deviceAddress);
obj.error = 0;
obj.index++;
if(obj.index < obj.lengthOfActualDeviceStream) setTimeout(obj.readRegisters, 0);
else obj.setNewStream();
}).catch (function () {
console.log("error pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute);
obj.error++;
if(obj.error == obj.lengthOfActualDeviceStream)
{
instance.send(instanceSendTo.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer
//todo - neposlalo notification, ked sme vypojili twilight a neposle to do tb, ale do dido ??
if(!numberOfNotResponding.hasOwnProperty(obj.device))
{
let message = "";
if(obj.device == "twilight_sensor")
{
message = "twilight_sensor_nok";
}
else if(obj.device == "em340")
{
message = "electrometer_nok";
}
message && sendNotification("modbus_reader: readingTimeouted", tbName, message, {}, "", instanceSendTo.tb, instance);
numberOfNotResponding[obj.device] = 1;
}
obj.error = 0;
numberOfNotResponding[obj.device] += 1;
}
console.error(require('util').inspect(arguments, {
depth: null
}))
obj.index++;
if(obj.index < obj.lengthOfActualDeviceStream) setTimeout(obj.readRegisters, 0);
else obj.setNewStream();
})
};
transformResponse = (response, register, deviceAddress) => {
for (let i = 0; i < this.lengthOfActualDeviceStream; i++) {
let a = this.stream[i];
if (a.register === register)
{
let tbAttribute = a.tbAttribute;
let multiplier = a.multiplier;
let value = this.calculateValue(response, multiplier);
// console.log(deviceAddress, register, tbName, tbAttribute, response, a.multiplier, value);
// if(tbName == undefined) return;
if(this.index + 1 + this.errors < this.lengthOfActualDeviceStream)
{
this.allValues[tbAttribute] = value;
return;
}
const values = {
...this.allValues,
[tbAttribute]: value,
};
this.checkNullVoltage(values);
instance.send(instanceSendTo.dido_controller, {values: values});
this.allValues = {};
break;
}
}
}
setNewStream = () =>
{
// console.log('------------',this.lengthOfActualDeviceStream, this.index);
// console.log('------------',this.indexInDeviceConfig, deviceConfig.length);
if(this.lengthOfActualDeviceStream == this.index)
{
if(this.indexInDeviceConfig + 1 == deviceConfig.length)
{
this.indexInDeviceConfig = 0;
}
else
{
this.indexInDeviceConfig += 1;
}
this.getActualStreamAndDevice();
}
}
// sendFinalObjects = (values) =>
// {
// const date = Date.now();
// // values["status"] = "OK";
// const dataToTB = {
// [tbName]: [
// {
// "ts": date,
// "values": values
// }
// ]
// };
// instance.send(instanceSendTo.tb, dataToTB);
// const dataToDiDo = {
// values: values
// }
// instance.send(instanceSendTo.dido_controller, dataToDiDo);
// }
calculateValue = (response, multiplier) =>
{
let value = 0;
let l = response.length;
if (l === 2)
{
value = (response[1]*(2**16) + response[0]);
if(value >= (2**31)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x80000000), ak vieš robiť logický súčin
{
value = value - "0xFFFFFFFF" + 1;
}
}
else if (l === 1)
{
value = response[0];
if(value >= (2**15)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x8000), ak vieš robiť logický súčin
{
value = value - "0xFFFF" + 1;
}
}
return Math.round(value * multiplier * 10) / 10;
}
checkNullVoltage = (values) => {
if(!(values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_2_voltage") || values.hasOwnProperty("Phase_3_voltage"))) return;
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();
// console.log(values[singleValue], tbName);
if(values[singleValue] == 0)
{
FLOW.OMS_no_voltage.add(phase);
sendNotification("modbus_citys: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase );
// console.log('no voltage')
}
else
{
FLOW.OMS_no_voltage.delete(phase);
// console.log('voltage detected')
sendNotification("modbus_citys: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase);
}
}
})
}
// we use dataToTbHandler. Therefore we need to check, if objects we send to dido_controller are not empty
isObjectEmpty = (objectName) => {
return Object.keys(objectName).length === 0 && objectName.constructor === Object;
}
}
setTimeout(() => {
const newSocket = new SocketWithClients();
tbName = FLOW.OMS_rvo_tbname;
}, 25000);
}

View file

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

View file

@ -245,6 +245,7 @@ exports.install = function(instance) {
} }
instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message }); instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message });
}); });
broker.on('close', function(err) { broker.on('close', function(err) {

View file

@ -6,12 +6,10 @@
"dependencies": { "dependencies": {
"bitwise": "^2.1.0", "bitwise": "^2.1.0",
"easy-crc": "0.0.2", "easy-crc": "0.0.2",
"jsmodbus": "^4.0.6",
"log4js": "^6.3.0", "log4js": "^6.3.0",
"mqtt": "^4.2.6", "mqtt": "^4.2.6",
"nodemailer": "^6.9.7",
"serialport": "^9.2.8", "serialport": "^9.2.8",
"total.js": "^3.4.13" "total.js": "^3.4.5"
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"

174
saved_data/modbus_settings Normal file
View file

@ -0,0 +1,174 @@
{
"config":{
"isRunning":false,
"debug":true,
"timeoutTime":4000,
"msgWaitTime":17000,
"port":"/dev/ttymxc0",
"port_options":"stty -F /dev/ttymxc0 9600 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke"
},
"private":{
"errBuffer":[
],
"tbBuffer":[
],
"device_index":0,
"cmd_index":0,
"devices":[
{
"name":"Elektrometer 1",
"tb_name":"",
"type":"EM340",
"address":1,
"data":[
],
"cmd":[
],
"timeoutcount":0,
"status":"virtual"
},
{
"name":"Twilight sensor",
"tb_name":"",
"type":"twilight",
"address":2,
"data":[
],
"cmd":[
],
"timeoutcount":0,
"status":"virtual"
}
],
"cmd_tables":[
{
"type":"EM340",
"cmd":[
{
"name":"Voltage L1",
"tb_name":"Phase_1_voltage",
"register":0,
"size":2,
"multiplier":0.1
},
{
"name":"Voltage L2",
"tb_name":"Phase_2_voltage",
"register":2,
"size":2,
"multiplier":0.1
},
{
"name":"Voltage L3",
"tb_name":"Phase_3_voltage",
"register":4,
"size":2,
"multiplier":0.1
},
{
"name":"Current L1",
"tb_name":"Phase_1_current",
"register":12,
"size":2,
"multiplier":0.001
},
{
"name":"Current L2",
"tb_name":"Phase_2_current",
"register":14,
"size":2,
"multiplier":0.001
},
{
"name":"Current L3",
"tb_name":"Phase_3_current",
"register":16,
"size":2,
"multiplier":0.001
},
{
"name":"Power L1",
"tb_name":"Phase_1_power",
"register":18,
"size":2,
"multiplier":0.1
},
{
"name":"Power L2",
"tb_name":"Phase_2_power",
"register":20,
"size":2,
"multiplier":0.1
},
{
"name":"Power L3",
"tb_name":"Phase_3_power",
"register":22,
"size":2,
"multiplier":0.1
},
{
"name":"Power tot",
"tb_name":"total_power",
"register":40,
"size":2,
"multiplier":0.1
},
{
"name":"Energy in",
"tb_name":"total_energy",
"register":52,
"size":2,
"multiplier":0.1
},
{
"name":"PowF L1",
"tb_name":"Phase_1_pow_factor",
"register":46,
"size":1,
"multiplier":0.001
},
{
"name":"PowF L2",
"tb_name":"Phase_2_pow_factor",
"register":47,
"size":1,
"multiplier":0.001
},
{
"name":"PowF L3",
"tb_name":"Phase_3_pow_factor",
"register":48,
"size":1,
"multiplier":0.001
},
{
"name":"PowF",
"tb_name":"power_factor",
"register":49,
"size":1,
"multiplier":0.001
}
]
},
{
"type":"twilight",
"cmd":[
{
"name":"Twilight",
"tb_name":"twilight_sensor",
"register":60,
"size":2,
"multiplier":1
}
]
}
]
}
}