2024-04-13 20:29:31 +02:00
exports . id = 'cmd_manager' ;
exports . title = 'CMD Manager' ;
exports . group = 'Worksys' ;
exports . color = '#5D9CEC' ;
exports . version = '0.0.3' ;
exports . output = [ 'red' , 'blue' , 'yellow' , 'blue' , 'white' ] ;
//blue - send message to relays
exports . input = true ;
exports . author = 'Daniel Segeš' ;
exports . icon = 'cloud-upload' ;
//exports.npm = ['serialport' , 'child_process'];
exports . html = `
< div class = "padding" >
< div class = "row" >
< div class = "col-md-12" >
< div > RPC - run RPC calls < / d i v > < b r >
< / d i v >
< / d i v >
2024-04-13 21:46:15 +02:00
< div data - jc = "textbox" data - jc - path = "username" class = "m" data - jc - config = "required:true" > @ ( User ) < / d i v >
< div class = "row" >
< div class = "col-md-6 m" >
< div data - jc = "textbox" data - jc - path = "userpassword" data - jc - config = "required:true" > @ ( Password ) < / d i v >
< / d i v >
< div class = "col-md-6 m" >
< div data - jc = "textbox" data - jc - path = "edge" data - jc - config = "required:true" > @ ( My edge ) < / d i v >
< / d i v >
< / d i v >
2024-04-13 20:29:31 +02:00
< / d i v >
` ;
exports . readme = ` Manager for CMD calls ` ;
const SerialPort = require ( 'serialport' ) ;
const { exec } = require ( 'child_process' ) ;
const { crc8 , crc16 , crc32 } = require ( 'easy-crc' ) ;
const { openPort , runSyncExec , writeData } = require ( './helper/serialport_helper.js' ) ;
const { bytesToInt , longToByteArray , addZeroBefore , isEmptyObject , convertUTCDateToLocalDate } = require ( './helper/utils' ) ;
const bitwise = require ( 'bitwise' ) ;
var SunCalc = require ( './helper/suncalc.js' ) ;
const DataToTbHandler = require ( './helper/DataToTbHandler.js' ) ;
const ErrorToServiceHandler = require ( './helper/ErrorToServiceHandler.js' ) ;
const { promisifyBuilder } = require ( './helper/db_helper.js' ) ;
const { sendNotification , initNotifications , ERRWEIGHT } = require ( './helper/notification_reporter.js' ) ;
//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
var path = require ( 'path' ) ;
var log4js = require ( "log4js" ) ;
const process = require ( 'process' ) ;
log4js . configure ( {
appenders : {
errLogs : { type : 'file' , compress : true , daysToKeep : 2 , maxLogSize : 1048576 , backups : 1 , keepFileExt : true , 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" ) ;
//USAGE
//logger.debug("text")
//monitor.info('info');
//errLogger.error("some error");
//load from settings
let latitude = 48.70826502 ; //48.682255758;
let longitude = 17.28455203 ; //17.278910807;
const gmtOffset = 0 ;
//ak nie je nastaveny
//https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
//https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
//priorities for registers
let priorities = [ ] ;
2024-04-13 21:46:15 +02:00
let minutes = 0.2 ;
2024-04-13 20:29:31 +02:00
priorities [ "1" ] = minutes ;
2024-04-13 21:46:15 +02:00
priorities [ "42" ] = minutes ;
minutes = 1 ;
priorities [ "0" ] = minutes ;
priorities [ "104" ] = minutes ;
2024-04-13 20:29:31 +02:00
minutes = 5 ;
priorities [ "74" ] = minutes ;
priorities [ "75" ] = minutes ;
priorities [ "76" ] = minutes ;
priorities [ "77" ] = minutes ;
priorities [ "78" ] = minutes ;
priorities [ "79" ] = minutes ;
priorities [ "84" ] = minutes ;
minutes = 10 ;
priorities [ "87" ] = minutes ;
priorities [ "6" ] = minutes ;
priorities [ "7" ] = minutes ;
priorities [ "80" ] = minutes ;
priorities [ "8" ] = minutes ;
priorities [ "3" ] = minutes ;
priorities [ "89" ] = minutes ;
2024-04-13 21:46:15 +02:00
priorities [ "95" ] = minutes ;
2024-04-13 20:29:31 +02:00
//prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app
2024-04-13 21:46:15 +02:00
let listOfCommands = [ 0 , 1 , 3 , 6 , 7 , 8 , 42 , 74 , 75 , 76 , 77 , 78 , 79 , 80 , 84 , 87 , 89 , 95 , 104 ] ;
2024-04-13 20:29:31 +02:00
//1 - dimming
const dbNodes = TABLE ( "nodes" ) ;
const dbRelays = TABLE ( "relays" ) ;
const dbSettings = TABLE ( "settings" ) ;
const errorHandler = new ErrorToServiceHandler ( ) ;
let rotary _switch _state = "Off" ;
let lux _sensor ;
let state _of _breaker = { } ; //key is line, value is On/Off
let disconnectedReport = { } ; //key is tbname, value true/false
let relaysData = { } ; //key is line, value is data from db
let nodesData = { } ; //key is node, value data from db
//helper container for counting resolved group of commands (commands related to set profile)
let cmdCounter = { } ; //key is node, value is counter
let cmdNOKNodeCounter = { } ; //key is node, value is counter
function cmdCounterResolve ( address )
{
if ( cmdCounter . hasOwnProperty ( address ) )
{
cmdCounter [ address ] = cmdCounter [ address ] - 1 ;
let result = cmdCounter [ address ] ;
if ( result == 0 ) delete cmdCounter [ address ] ;
return result ;
}
return - 1 ;
}
function getParams ( priority )
{
let params = { } ;
//core rpc values
params . address = 0 ; //if(recipient === 0) address = 0;
params . byte1 = 0 ; //msb, podla dokumentacie data3
params . byte2 = 0 ; //podla dokumentacie data2
params . byte3 = 0 ; //podla dokumentacie data1
params . byte4 = 0 ; //lsb, podla dokumentacie data0
params . recipient = 0 ; //0: Master, 1: Slave, 2: Broadcast
params . register = - 1 ; //register number
params . rw = 0 ; //0: read, 1: write
//other values
//params.type = "cmd"; "relay" "cmd-terminal"
//params.tbname = tbname;
params . priority = priorityTypes . node _cmd ; //default priority
params . timestamp = 0 ; //execution time
if ( priority != undefined )
{
params . timestamp = priority ;
params . priority = priority ;
}
params . addMinutesToTimestamp = 0 ; //repeat if > 0,
//params.isDusk = false;
//params.isDawn = false;
//params.info = "";
return params ;
}
async function loadSettings ( )
{
let responseSettings = await promisifyBuilder ( dbSettings . find ( ) ) ;
latitude = responseSettings [ 0 ] [ "latitude" ] ;
longitude = responseSettings [ 0 ] [ "longitude" ] ;
//globals
FLOW . OMS _language = responseSettings [ 0 ] [ "lang" ] ;
FLOW . OMS _rvo _name = responseSettings [ 0 ] [ "rvo_name" ] ;
FLOW . OMS _projects _id = responseSettings [ 0 ] [ "projects_id" ] ;
//FLOW.OMS_rvo_tbname = responseSettings[0]["tbname"];
FLOW . OMS _temperature _adress = responseSettings [ 0 ] [ "temperature_adress" ] ;
FLOW . OMS _controller _type = responseSettings [ 0 ] [ "controller_type" ] ;
FLOW . OMS _serial _port = responseSettings [ 0 ] [ "serial_port" ] ;
//logger.log("", "settings", responseSettings[0], "-------------------------------------");
logger . debug ( 'settings' , responseSettings [ 0 ] ) ;
//FLOW.OMS_tem
//rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number
initNotifications ( ) ;
}
//nastav profil nodu
function processNodeProfile ( node )
{
if ( rotary _switch _state != "Automatic" )
{
logger . debug ( "unable to process profile for node" , node , "rotary_switch_state != Automatic" ) ;
return ;
}
let nodeObj = nodesData [ node ] ;
let line = nodeObj . line ;
if ( relaysData [ line ] . contactor == 0 )
{
logger . debug ( "line line is off" , line , node ) ;
return ;
}
if ( nodeObj . processed == 1 )
{
logger . debug ( "node was already processed" , node ) ;
return ;
}
let profile = nodeObj . profile ;
logger . debug ( "processNodeProfile: start - set profile for " , node , profile ) ;
let nodeProfile ;
2024-04-13 21:46:15 +02:00
try {
2024-04-13 20:29:31 +02:00
nodeProfile = JSON . parse ( profile ) ;
2024-04-13 21:46:15 +02:00
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" ) ;
}
2024-04-13 20:29:31 +02:00
} catch ( error ) { }
//test reset profilu
//nodeProfile = undefined;
logger . debug ( "processNodeProfile" , node , line , nodeObj , nodeProfile ) ;
//return;
//let timestamp = priorityTypes.node_cmd;
//let now = new Date();
//now.setSeconds(now.getSeconds() + 10);
//let timestamp = now.getTime();
let timestamp = priorityTypes . node _cmd ;
//nodeProfile = undefined;
removeTask ( { type : "set_node_profile" , address : node } ) ;
cmdNOKNodeCounter [ node ] = 0 ;
//co ked sa prave spracovava?
//if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
if ( nodeProfile === undefined )
{
//vypneme profil nodu, posleme cmd
//Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
//Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
logger . debug ( "turn off profile" ) ;
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . byte1 = 0 ;
params . byte2 = 0 ;
params . byte3 = 0 ;
params . byte4 = 32 ;
params . recipient = 1 ;
params . register = 8 ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = 'turn off/reset node profile' ;
cmdCounter [ node ] = 1 ;
tasks . push ( params ) ;
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", instanceSendTo.tb, instance );
}
else
{
let tasksProfile = [ ] ;
//cmdCounter[node] = tasksProfile.length;
//tasks.push(tasksProfile);
//let timestamp = priorityTypes.node_cmd;
2024-04-13 21:46:15 +02:00
//vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
2024-04-13 20:29:31 +02:00
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . byte1 = 0 ;
params . byte2 = 0 ;
params . byte3 = 0 ;
params . byte4 = 32 ;
params . recipient = 1 ;
params . register = 8 ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = 'turn off node profile' ;
tasksProfile . push ( params ) ;
timestamp ++ ;
logger . debug ( "processNodeProfile: TS1 Time point a TS1 Time Point Levels " , node ) ;
2024-04-13 21:46:15 +02:00
// "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"
// }
// ]
2024-04-13 20:29:31 +02:00
//TS1 Time point a TS1 Time Point Levels
let register = 9 ;
for ( let i = 0 ; i < nodeProfile . intervals . length ; i ++ )
{
let obj = nodeProfile . intervals [ i ] ;
//let timePoint = obj.time_point;
let dim _value = obj . value ;
2024-04-13 21:46:15 +02:00
let cct = obj . cct ;
2024-04-13 20:29:31 +02:00
//Reg 9 až Reg 40
/ *
Samotný profil sa zapisuje do max . 16 párov – časový bod a úroveň .
Prázdny profil je vtedy keď časový bod obsahuje hodnotu 0xFFFFFFFF ( táto hodnota sa zapíše do registrov keď sa aktivuje reset profilu do registru 8 ) .
Páry sa prechádzajú časovo zoradené takže teoreticky je jedno v akom poradí sa zapisujú ale je lepšie ich zapisovať v chronologickom poradí od 13 : 00.
Časový bod má formát :
2024-04-13 21:46:15 +02:00
Byte 3 : hodiny Byte 2 : minúty Byte 1 : sekundy Byte 0 – rezervované
2024-04-13 20:29:31 +02:00
Register úrovne má rovnaký formát ako dimming register ( Reg 1 ) .
* /
2024-04-13 21:46:15 +02:00
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//params.byte1 = 0;//msb, podla dokumentacie data3
//params.byte2 = 0;//podla dokumentacie data2
//params.byte3 = 0;//podla dokumentacie data1
//params.byte4 = 0;//lsb, podla dokumentacie data0
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2024-04-13 20:29:31 +02:00
let start _time = obj . start _time ;
let t = start _time . split ( ":" ) ;
//if(timePoint != undefined) t = timePoint.split(":");
//else t = [0,0];
logger . debug ( "processNodeProfile: TS1 Time point " , ( i + 1 ) , node ) ;
params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . byte1 = parseInt ( t [ 0 ] ) ; //hh
params . byte2 = parseInt ( t [ 1 ] ) ; //mm
params . byte3 = 0 ; //ss
params . byte4 = 0 ; //
params . recipient = 1 ;
params . register = register ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = 'TS1 Time point ' + ( i + 1 ) ;
tasksProfile . push ( params ) ;
register ++ ;
timestamp ++ ;
2024-04-13 21:46:15 +02:00
// 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 ) ;
2024-04-13 20:29:31 +02:00
params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
2024-04-13 21:46:15 +02:00
params . byte1 = 1 ;
params . byte2 = byte2 ;
params . byte3 = byte3 ;
params . byte4 = parseInt ( dim _value ) + 128 ;
2024-04-13 20:29:31 +02:00
params . recipient = 1 ;
params . register = register ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = 'TS1 Time point Levels ' + ( i + 1 ) ;
tasksProfile . push ( params ) ;
register ++ ;
timestamp ++ ;
}
//Threshold lux level for DUSK/DAWN
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//params.byte1 = 0;//msb, podla dokumentacie data3
//params.byte2 = 0;//podla dokumentacie data2
//params.byte3 = 0;//podla dokumentacie data1
//params.byte4 = 0;//lsb, podla dokumentacie data0
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Time schedule settings na koniec
//if(nodeProfile.dusk_lux_sensor || nodeProfile.dawn_lux_sensor)
{
logger . debug ( "processNodeProfile: Threshold lux level for DUSK/DAWN" , node ) ;
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . register = 96 ;
params . recipient = 1 ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = "Threshold lux level for DUSK/DAWN" ;
if ( nodeProfile . dusk _lux _sensor )
{
let v = nodeProfile . dusk _lux _sensor _value ;
let ba = longToByteArray ( v ) ;
params . byte1 = ba [ 1 ] ; //msb
params . byte2 = ba [ 0 ] ;
}
if ( nodeProfile . dawn _lux _sensor )
{
let v = nodeProfile . dawn _lux _sensor _value ;
let ba = longToByteArray ( v ) ;
params . byte3 = ba [ 1 ] ; //msb
params . byte4 = ba [ 0 ] ;
}
tasksProfile . push ( params ) ;
timestamp ++ ;
}
//DUSK/DAWN max. adjust period
{
logger . debug ( "processNodeProfile: DUSK/DAWN max. adjust period" , node ) ;
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . register = 97 ;
params . recipient = 1 ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = "DUSK/DAWN max. adjust period" ;
if ( nodeProfile . astro _clock )
{
let v = nodeProfile . dusk _lux _sensor _time _window ;
let ba = longToByteArray ( v ) ;
params . byte1 = ba [ 1 ] ; //msb
params . byte2 = ba [ 0 ] ;
}
if ( nodeProfile . astro _clock )
{
let v = nodeProfile . dawn _lux _sensor _time _window ;
let ba = longToByteArray ( v ) ;
params . byte3 = ba [ 1 ] ; //msb
params . byte4 = ba [ 0 ] ;
}
tasksProfile . push ( params ) ;
timestamp ++ ;
}
//Static offset
{
//Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
2024-04-13 21:46:15 +02:00
//Bity 0 – 6: hodnota v minútach
//Bit 7: znamienko (1 – mínus)
2024-04-13 20:29:31 +02:00
logger . debug ( "processNodeProfile: Static offset" , node ) ;
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . register = 98 ;
params . recipient = 1 ;
params . rw = 1 ; //write
params . timestamp = timestamp ;
params . addMinutesToTimestamp = 0 ;
params . info = "Static offset" ;
if ( nodeProfile . astro _clock )
{
let dusk _astro _clock _offset = parseInt ( nodeProfile . dusk _astro _clock _offset ) ;
let dawn _astro _clock _offset = parseInt ( nodeProfile . dawn _astro _clock _offset ) ;
if ( dusk _astro _clock _offset < 0 )
{
params . byte3 = ( dusk _astro _clock _offset * - 1 ) + 128 ;
}
else
{
params . byte3 = dusk _astro _clock _offset ;
}
if ( dawn _astro _clock _offset < 0 )
{
params . byte4 = ( dawn _astro _clock _offset * - 1 ) + 128 ;
}
else
{
params . byte4 = dawn _astro _clock _offset ;
}
}
tasksProfile . push ( params ) ;
timestamp ++ ;
}
logger . debug ( "Time schedule settings - turn on" , node ) ;
params = getParams ( priorityTypes . node _cmd ) ;
params . type = "set_node_profile" ;
params . address = node ;
params . register = 8 ;
params . recipient = 1 ;
params . rw = 1 ; //write
//Time schedule settings
let bits = [ ] ;
//Byte 0 (LSB):
//Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
bits . push ( 1 ) ;
//Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
bits . push ( 0 ) ;
bits . push ( 0 ) ;
bits . push ( 0 ) ;
if ( nodeProfile . astro _clock == true )
{
//Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
bits . push ( 1 ) ;
}
else bits . push ( 0 ) ;
//Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
bits . push ( 0 ) ;
2024-04-13 21:46:15 +02:00
//Bity 6-7 - zatiaľ nepoužité
2024-04-13 20:29:31 +02:00
bits . push ( 0 ) ;
bits . push ( 0 ) ;
params . byte4 = bitwise . byte . write ( bits . reverse ( ) ) ;
//Byte 2 – nastavenie pre lux senzor:
bits = [ ] ;
//Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
if ( nodeProfile . dusk _lux _sensor == true ) //sumrak
{
bits . push ( 1 ) ;
}
else bits . push ( 0 ) ;
//Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
if ( profile . dawn _lux _sensor == true ) //usvit
{
bits . push ( 1 ) ;
}
else bits . push ( 0 ) ;
//Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
bits . push ( 0 ) ; //zatial neimplementovane
//Bit 3 – 7 - nepoužité
bits . push ( 0 ) ;
bits . push ( 0 ) ;
bits . push ( 0 ) ;
bits . push ( 0 ) ;
bits . push ( 0 ) ;
params . byte2 = bitwise . byte . write ( bits . reverse ( ) ) ;
params . timestamp = timestamp ;
params . info = "Time schedule settings - turn on" ;
tasksProfile . push ( params ) ;
//zaver
cmdCounter [ node ] = tasksProfile . length ;
//tasks.push(tasksProfile);
tasks = tasks . concat ( tasksProfile ) ;
}
logger . debug ( "finished set profile for " , node ) ;
}
const instanceSendTo = {
debug : 0 ,
tb : 1 ,
http _response : 2 ,
2024-04-13 21:46:15 +02:00
di _do _controller : 3 ,
2024-04-13 20:29:31 +02:00
infoSender : 4
}
const priorityTypes = {
terminal : 0 ,
fw _detection : 1 , //reserved only for FW detection - FLOW.OMS_masterNodeIsResponding
high _priority : 2 , //reserverd only for: read dimming / brightness (after set dimming from platform)
relay _profile : 3 ,
node _broadcast : 4 ,
node _profile : 5 ,
node _cmd : 6
}
let interval = null ; //timeout for procesing tasks
let refFlowdata = null ; //holds reference to httprequest flowdata
let refFlowdataObj = { } ;
function cleanUpRefFlowdataObj ( )
{
let now = new Date ( ) ;
let timestamp = now . getTime ( ) ;
//clear old refFlowdata references
let keys = Object . keys ( refFlowdataObj ) ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let timestampKey = keys [ i ] ;
if ( ( timestamp - timestampKey ) > 60 * 1000 )
{
console . log ( "cleanUpRefFlowdataObj delete" , timestampKey ) ;
delete refFlowdataObj [ timestampKey ] ;
}
}
}
let tasks = [ ] ; //list of command calls to process
function removeTask ( obj )
{
let keys = Object . keys ( obj ) ;
tasks = tasks . filter ( ( task ) => {
let counter = 0 ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let key = keys [ i ] ;
if ( task . hasOwnProperty ( key ) && obj . hasOwnProperty ( key ) )
{
if ( task [ key ] == obj [ key ] ) counter ++ ;
}
}
if ( counter == keys . length ) return false ;
return true ;
} ) ;
}
//TODO - to remove?
const shortIterval = 10 ;
const longInterval = 100 ;
loadSettings ( ) ;
exports . install = function ( instance ) {
process . on ( 'uncaughtException' , function ( err ) {
//TODO send to service
errLogger . error ( 'uncaughtException:' , err . message )
errLogger . error ( err . stack ) ;
errorHandler . sendMessageToService ( err . message + "\n" + err . stack , 0 , "js_error" ) ;
//process.exit(1);
} )
//te();//force error
const tbHandler = new DataToTbHandler ( instanceSendTo . tb ) ;
tbHandler . setSender ( exports . title ) ;
//FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name
//const errorHandler = new ErrorToServiceHandler(instance, instanceSendTo.infoSender);
errorHandler . setProjectsId ( FLOW . OMS _projects _id ) ;
//const errorHandler = new ErrorToServiceHandler(instance);
//errorHandler.sendMessageToService("ahoj", 0);
async function loadRelaysData ( line )
{
logger . debug ( "loadRelaysData" , line ) ;
//ak zapiname liniu, mali by sme skontrolovat kde processed je false
//nodes.table: node:number|tbname:string|line:number|profile:string|processed:boolean
//vyselektujem vsetky nodes a spracujem profil
return new Promise ( ( resolve , reject ) => {
dbRelays . find ( ) . make ( function ( builder ) {
builder . callback ( function ( err , response ) {
if ( err != null ) reject ( err ) ;
let relaysDataTmp = { } ;
for ( let i = 0 ; i < response . length ; i ++ )
{
let record = response [ i ] ;
let line = record [ "line" ] ;
relaysDataTmp [ record [ "line" ] ] = record ;
//porovname predchadzajuce hodnoty
//ak record.contactor == 1, a aktualna hodnota record.contactor == 0
//to znamena, ze sa zmenil stav - linia bola vypnuta
let prevData = relaysData [ record [ "line" ] ] ;
//ugly but do not remove!!!
relaysData [ record [ "line" ] ] = record ;
let state = "" ; //on, off or empty (no change)
if ( prevData != undefined )
{
/ *
if ( prevData . contactor == 1 && record . contactor == 0 )
{
state = "off" ;
reportOfflineNodeStatus ( line ) ;
}
if ( prevData . contactor == 0 && record . contactor == 1 )
{
state = "on" ;
reportOnlineNodeStatus ( line ) ;
}
* /
}
else
{
//start flowu
state = "start" ;
}
if ( line != undefined )
{
//ak sa jedna o update profilu linie - pozor di_co_controller posiela command pre loadRelaysData
if ( line != record [ "line" ] ) continue ;
}
//je zapnuta linia? contactor = 1 a processed = false, spracujeme profil
if ( record . contactor == 1 )
{
//nespracovany profil, zapisem do nodu
//rotary_switch_state = Automatic - profilu pre nody sa vykonavaju
//ak je spracovany, a automatic - tak ho zapnem
if ( rotary _switch _state == "Automatic" )
{
//prejs nodes - nacitame vsetky nody z pre danu liniu
for ( let k in nodesData ) {
//node:number|tbname:string|line:number|profile:string|processed:boolean
2024-04-13 21:46:15 +02:00
let node = nodesData [ k ] ;
2024-04-13 20:29:31 +02:00
//potrebujem nody k danej linii
2024-04-13 21:46:15 +02:00
if ( record . line == node . line )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
let address = node . node ;
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 )
}
2024-04-13 20:29:31 +02:00
if ( ! processed )
{
2024-04-13 21:46:15 +02:00
console . log ( '=====procesujem profille' )
processNodeProfile ( address ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
else
{
2024-04-13 20:29:31 +02:00
//logger.debug( `node ${node} profile for line ${nodesData[k].line} was already processed`);
}
}
}
}
else
{
logger . debug ( "unable to process profile - rotary_switch_state is" , rotary _switch _state ) ;
}
}
}
relaysData = { ... relaysDataTmp } ;
resolve ( "OK" ) ;
} ) ;
} ) ;
//resolve(stdout);
//reject(error);
} )
}
function reportOnlineNodeStatus ( line )
{
//broadcast cas, o 1-2 sek neskor - status, brightness
//Po zapnutí línie broadcastovo aktualizovať predtým čas.
logger . debug ( "--->reportOnlineNodeStatus for line" , line ) ;
//return;
{
//run broadcast //Actual time
addMinutesToTimestamp = 0 ;
let params = { } ;
let recipient = 2 ; //2 broadcast, address = 0
let address = 0 ; //0
if ( recipient === 2 )
{
address = 0xffffffff ; //Broadcast
}
var d = new Date ( ) ;
let hours = d . getHours ( ) ;
let minutes = d . getMinutes ( ) ;
let seconds = d . getSeconds ( ) ;
params . address = address ; //broadcast
params . byte1 = hours ; //h
params . byte2 = minutes ; //m
params . byte3 = seconds ; //s
params . byte4 = 0 ;
params . recipient = recipient ;
params . register = 87 ; //Actual time
params . rw = 1 ; //write
let timestampStart = priorityTypes . node _broadcast ;
//other values
params . type = "cmd" ;
//params.tbname = tbname;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = addMinutesToTimestamp ;
params . info = "run broadcast: Actual time" ;
tasks . push ( params ) ;
let sec = 3 ;
setTimeout ( function ( ) {
//Po zapnutí línie - spraviť hromadný refresh stavu práve zapnutých svietidiel
for ( let k in nodesData ) {
//potrebujem nody k danej linii
if ( line == nodesData [ k ] . line || line == undefined )
{
let tbname = nodesData [ k ] . tbname ;
let node = nodesData [ k ] . node ;
//prud, vykon - current, input power pre liniu pre vsetky nody
//a pridame aj vyreportovanie dimmingu
{
let params = getParams ( priorityTypes . high _priority ) ;
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 = 'read dimming / brightness (after set dimming from platform)' ;
//params.debug = true;
tasks . push ( params ) ;
}
//Prúd
{
let params = getParams ( priorityTypes . high _priority ) ;
params . type = "cmd" ;
params . tbname = tbname ;
params . address = node ;
params . register = 75 ; //prud
params . recipient = 1 ; //slave
params . rw = 0 ; //read
params . timestamp = priorityTypes . high _priority ;
params . info = 'read current (after set dimming from platform)' ;
//params.debug = true;
tasks . push ( params ) ;
}
//výkon
{
let params = getParams ( priorityTypes . high _priority ) ;
params . type = "cmd" ;
params . tbname = tbname ;
params . address = node ;
params . register = 76 ; //výkon
params . recipient = 1 ; //slave
params . rw = 0 ; //read
params . timestamp = priorityTypes . high _priority ;
params . info = 'read power (after set dimming from platform)' ;
//params.debug = true;
tasks . push ( params ) ;
}
}
}
} , sec * 1000 ) ;
}
}
function reportOfflineNodeStatus ( line )
{
logger . debug ( "--->reportOfflineNodeStatus for line" , line ) ;
values = { } ;
values [ "dimming" ] = 0 ; //brightness
values [ "power" ] = 0 ; //výkon
values [ "current" ] = 0 ; //prúd
values [ "status" ] = "OFFLINE" ; //prúd
for ( let k in nodesData ) {
//potrebujem nody k danej linii
if ( line == nodesData [ k ] . line || line == undefined )
{
let tbname = nodesData [ k ] . tbname ;
//logger.debug("node:", tbname);
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
}
}
//report OFFLINE for line
//relaysData[line].tbname;
//values = {};
//values["status"] = "OFFLINE";//prúd
}
let now = new Date ( ) ;
console . log ( "CMD Manager installed" , now . toLocaleString ( "sk-SK" ) ) ;
function turnOnLine ( line , info )
{
let obj = {
line : line ,
command : "turnOn" ,
info : info
} ;
logger . debug ( "linia" , line , obj ) ;
2024-04-13 21:46:15 +02:00
instance . send ( instanceSendTo . di _do _controller , obj ) ;
2024-04-13 20:29:31 +02:00
}
function turnOffLine ( line , info )
{
let obj = {
line : line ,
command : "turnOff" ,
info : info
} ;
logger . debug ( "linia" , line , obj ) ;
2024-04-13 21:46:15 +02:00
instance . send ( instanceSendTo . di _do _controller , obj ) ;
2024-04-13 20:29:31 +02:00
}
function detectIfResponseIsValid ( bytes )
{
//ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
let type = "RESPONSE" ;
if ( bytes [ 4 ] == 0 ) type = "RESPONSE" ;
else if ( bytes [ 4 ] == 1 ) type = "ERROR" ;
else if ( bytes [ 4 ] == 2 ) type = "EVENT" ;
else type = "UNKNOWN" ;
let crc = crc16 ( 'ARC' , bytes . slice ( 0 , 9 ) ) ;
let c1 = ( crc >> 8 ) & 0xFF ;
let c2 = crc & 0xFF ;
let message = "OK" ;
let error = "" ;
if ( c1 != bytes [ 9 ] )
{
//CRC_ERROR
message = "NOK" ;
error = "CRC_ERROR c1" ;
instance . send ( instanceSendTo . debug , "CRC_ERROR c1" ) ;
}
if ( c2 != bytes [ 10 ] )
{
//CRC_ERROR
message = "NOK" ;
error = "CRC_ERROR c2" ;
instance . send ( instanceSendTo . debug , "CRC_ERROR c2" ) ;
}
//crc error
if ( type != "RESPONSE" )
{
instance . send ( instanceSendTo . debug , bytes ) ;
instance . send ( instanceSendTo . debug , "RESPONSE " + type + " - " + bytes [ 4 ] ) ;
//logger.debug(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4], bytes);
error = "type is: " + type ;
message = "NOK" ;
}
return { message : message , type : type , error : error } ;
}
function buildTasks ( params )
{
//report FLOW.OMS_edge_fw_version as fw_version
//report date as startdate
monitor . info ( "buildTasks - params" , params ) ;
let processLine ; //defined line
let init = false ;
let processLineProfiles = true ;
let processBroadcast = true ;
let processNodes = true ;
if ( params == undefined )
{
init = true ;
tasks = [ ] ;
logger . debug ( "-->buildTasks clear tasks" ) ;
}
else
{
processLineProfiles = false ;
processBroadcast = false ;
processNodes = false ;
processLineProfiles = params . processLineProfiles ;
processLine = params . line ;
}
//load profiles pre linie
//relaysData[ record["line"] ]
let now = new Date ( ) ;
if ( processLineProfiles )
{
//process line profiles
let keys = Object . keys ( relaysData ) ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let line = keys [ i ] ; //line is turned off by default
let profilestr = relaysData [ line ] . profile ;
//Reset linii
let resetLine = false ;
if ( FLOW . OMS _rvo _name == "Kovalov RVO 2" && line != '0' && init == true ) resetLine = true ;
if ( resetLine )
{
/ *
Takže v Koválove sú nastavené offesty pre dusk a dawn nasledovne :
DUSK : offset + 20 minút – teda napr . namiesto 17 : 00 bude 17 : 20 a reštart by sa robil v čase 17 : 19 , teda o minútu skôr . Tak aby keď budeš robiť zapnutie o 17 : 20 tak na RVO1 sa svietidlá zapnú v rovnakom čase . Teda : vypnutie v čase DUSK _TIME + 19 minút , zapnutie v čase DUSK _TIME + 20 minút
DAWN : offset - 30 minút – teda napr . namiesto 7 : 00 bude 6 : 30 a reštart by sa robil v čase 6 : 30 , tak aby sa svietidlá zhasli rovnako s RVO1 . Zapnutie by bolo 6 : 31.
Teda : vypnutie v čase DAWN _TIME - 30 minút , zapnutie v čase DAWN _TIME - 29 minút
Vždy po reštarte asi 30 sekúnd po zapnutí treba poslať aktuálny čas na nody .
* /
//function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0)
let duskOffset = 20 ;
let dawnOffset = - 30 ;
let sunCalcResult = calculateDuskDown ( new Date ( ) , undefined , duskOffset , dawnOffset ) ;
console . log ( sunCalcResult ) ;
//if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo
//if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo
//DUSK - sumrak
{
//vypneme liniu a o minitu zapneme
{
let value = 0 ; //vypneme liniu
let isDusk = true ;
let isDawn = false ;
let dusk _time = sunCalcResult . dusk _time ;
if ( dusk _time < now . getTime ( ) ) dusk _time = dusk _time + 24 * 60 * 60 * 1000 ; //1den
let params = getParams ( priorityTypes . relay _profile ) ;
params . type = "relay" ;
params . line = line ;
params . value = value ;
params . tbname = relaysData [ line ] . tbname ;
params . timestamp = dusk _time ;
params . duskOffset = duskOffset ;
params . useProfile = false ;
//once a day
params . addMinutesToTimestamp = 24 * 60 ;
//this will be recalculated
params . isDusk = isDusk ;
params . isDawn = isDawn ;
if ( params . value == 0 ) params . info = "reset - KOVALOV - force turn off line: " + line ;
else if ( params . value == 1 ) params . info = "reset - KOVALOV - force turn on line: " + line ;
params . debug = true ;
//turn on/off line
tasks . push ( params ) ;
console . log ( params ) ;
}
//a o minutu zapneme
{
let value = 1 ; //zapneme liniu
let isDusk = true ;
let isDawn = false ;
let dusk _time = sunCalcResult . dusk _time + 60 * 1000 ; //o minutu neskor po vypnuti zapneme
if ( dusk _time < now . getTime ( ) ) dusk _time = dusk _time + 24 * 60 * 60 * 1000 ; //1den
let params = getParams ( priorityTypes . relay _profile ) ;
params . type = "relay" ;
params . line = line ;
params . value = value ;
params . tbname = relaysData [ line ] . tbname ;
params . timestamp = dusk _time ;
params . duskOffset = duskOffset + 1 ;
params . useProfile = false ;
//once a day
params . addMinutesToTimestamp = 24 * 60 ;
//this will be recalculated
params . isDusk = isDusk ;
params . isDawn = isDawn ;
if ( params . value == 0 ) params . info = "reset - KOVALOV - force turn off line: " + line ;
else if ( params . value == 1 ) params . info = "reset - KOVALOV - force turn on line: " + line ;
params . debug = true ;
//turn on/off line
tasks . push ( params ) ;
console . log ( params ) ;
}
}
//DAWN - vychod
{
//vypneme liniu a o minitu zapneme
{
let value = 0 ; //vypneme liniu
let isDusk = false ;
let isDawn = true ;
let dawn _time = sunCalcResult . dawn _time ;
if ( dawn _time < now . getTime ( ) ) dawn _time = dawn _time + 24 * 60 * 60 * 1000 ; //1den
let params = getParams ( priorityTypes . relay _profile ) ;
params . type = "relay" ;
params . line = line ;
params . value = value ;
params . tbname = relaysData [ line ] . tbname ;
params . timestamp = dawn _time ;
params . dawnOffset = dawnOffset ;
params . useProfile = false ;
//once a day
params . addMinutesToTimestamp = 24 * 60 ;
//this will be recalculated
params . isDusk = isDusk ;
params . isDawn = isDawn ;
if ( params . value == 0 ) params . info = "reset - KOVALOV - force turn off line: " + line ;
else if ( params . value == 1 ) params . info = "reset - KOVALOV - force turn on line: " + line ;
params . debug = true ;
//turn on/off line
tasks . push ( params ) ;
console . log ( params ) ;
}
//a o minitu zapneme
{
let value = 1 ; //vypneme liniu
let isDusk = false ;
let isDawn = true ;
let dawn _time = sunCalcResult . dawn _time + 1000 * 60 ; //o minutu neskor po vypnuti zapneme
if ( dawn _time < now . getTime ( ) ) dawn _time = dawn _time + 24 * 60 * 60 * 1000 ; //1den
let params = getParams ( priorityTypes . relay _profile ) ;
params . type = "relay" ;
params . line = line ;
params . value = value ;
params . tbname = relaysData [ line ] . tbname ;
params . timestamp = dawn _time ;
params . dawnOffset = dawnOffset + 1 ;
params . useProfile = false ;
//once a day
params . addMinutesToTimestamp = 24 * 60 ;
//this will be recalculated
params . isDusk = isDusk ;
params . isDawn = isDawn ;
if ( params . value == 0 ) params . info = "reset - KOVALOV - force turn off line: " + line ;
else if ( params . value == 1 ) params . info = "reset - KOVALOV - force turn on line: " + line ;
params . debug = true ;
//turn on/off line
tasks . push ( params ) ;
console . log ( params ) ;
}
}
//console.log("-------------------------Kovalov RVO 2----");
}
if ( processLine != undefined )
{
if ( processLine != line ) continue ;
}
try {
if ( profilestr === "" ) throw ( "profile is not defined" ) ;
let profile = JSON . parse ( profilestr ) ;
if ( Object . keys ( profile ) . length === 0 ) throw ( "profile is not defined" ) ;
monitor . info ( "buildTasks: profile for line" , line ) ;
monitor . info ( "profile:" , profile ) ;
let time _points = profile . time _points ;
if ( time _points == undefined ) time _points = profile . intervals ;
2024-04-13 21:46:15 +02:00
// monitor.info("buildTasks: time_points", time_points);
2024-04-13 20:29:31 +02:00
let currentValue = 0 ;
if ( time _points . length > 0 ) currentValue = time _points [ time _points . length - 1 ] . value ;
//create task for tun on + turn off, calculate dusk/down
if ( profile . astro _clock == true )
{
//let now = new Date().toLocaleString("en-US", {timeZone: "Europe/Bratislava"});
let sunCalcResult = calculateDuskDown ( new Date ( ) , line ) ;
2024-04-13 21:46:15 +02:00
monitor . info ( "dusk and dawn sunCalcResult" , line , sunCalcResult ) ;
2024-04-13 20:29:31 +02:00
//add to timpoints
if ( profile . dawn _lux _sensor == false ) time _points . push ( { "start_time" : sunCalcResult [ "dawn" ] , "value" : 1 , "isDawn" : true } ) ;
if ( profile . dusk _lux _sensor == false ) time _points . push ( { "start_time" : sunCalcResult [ "dusk" ] , "value" : 0 , "isDusk" : true } ) ;
//aby nam to neostalo svietit
if ( profile . dawn _lux _sensor == true )
{
//force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
let [ ahours , aminutes , aseconds ] = sunCalcResult [ "dawn" ] . split ( ':' ) ;
let ad = new Date ( ) ;
ad . setHours ( parseInt ( ahours ) ) ;
ad . setMinutes ( parseInt ( aminutes ) + profile . dawn _lux _sensor _time _window ) ;
ad . setSeconds ( 0 ) ;
let strDate = ad . getHours ( ) + ":" + ad . getMinutes ( ) ;
time _points . push ( { "value" : 0 , "start_time" : strDate } ) ;
}
if ( profile . dusk _lux _sensor == true )
{
//force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
let [ ahours , aminutes , aseconds ] = sunCalcResult [ "dusk" ] . split ( ':' ) ;
let ad = new Date ( ) ;
ad . setHours ( parseInt ( ahours ) ) ;
ad . setMinutes ( parseInt ( aminutes ) + profile . dawn _lux _sensor _time _window ) ;
ad . setSeconds ( 0 ) ;
let strDate = ad . getHours ( ) + ":" + ad . getMinutes ( ) ;
time _points . push ( { "value" : 1 , "start_time" : strDate } ) ;
}
}
//sort time_points
time _points . sort ( function ( a , b ) {
let [ ahours , aminutes , aseconds ] = a . start _time . split ( ':' ) ;
let [ bhours , bminutes , bseconds ] = b . start _time . split ( ':' ) ;
let ad = new Date ( ) ;
ad . setHours ( parseInt ( ahours ) ) ;
ad . setMinutes ( parseInt ( aminutes ) ) ;
ad . setSeconds ( 0 ) ;
let bd = new Date ( ) ;
bd . setHours ( parseInt ( bhours ) ) ;
bd . setMinutes ( parseInt ( bminutes ) ) ;
ad . setSeconds ( 0 ) ;
return ad . getTime ( ) - bd . getTime ( ) ;
} ) ;
monitor . info ( "-->comming events turn on/off lines:" ) ;
for ( let t = 0 ; t < time _points . length ; t ++ )
{
let start _time = new Date ( ) ;
let isDusk = false ;
let isDawn = false ;
if ( time _points [ t ] . hasOwnProperty ( "isDusk" ) ) isDusk = time _points [ t ] . isDusk ;
if ( time _points [ t ] . hasOwnProperty ( "isDawn" ) ) isDawn = time _points [ t ] . isDawn ;
if ( isDusk ) time _points [ t ] . value = 1 ; //sumrak - zapneme svetlo
if ( isDawn ) time _points [ t ] . value = 0 ; //vychod - vypneme svetlo
if ( time _points [ t ] . hasOwnProperty ( "start_time" ) )
{
let [ hours , minutes , seconds ] = time _points [ t ] . start _time . split ( ':' ) ;
start _time . setHours ( parseInt ( hours ) ) ;
start _time . setMinutes ( parseInt ( minutes ) ) ;
start _time . setSeconds ( 0 ) ;
}
//task is the past
if ( now . getTime ( ) > start _time . getTime ( ) )
{
currentValue = time _points [ t ] . value ;
//je v minulosti, pridame 24h
start _time . setDate ( start _time . getDate ( ) + 1 ) ;
}
let params = getParams ( priorityTypes . relay _profile ) ;
params . type = "relay" ;
params . line = line ;
params . value = time _points [ t ] . value ;
params . tbname = relaysData [ line ] . tbname ;
params . timestamp = start _time . getTime ( ) ;
params . addMinutesToTimestamp = 0 ;
//once a day
if ( ! isDusk && ! isDawn ) params . addMinutesToTimestamp = 24 * 60 ;
//inak sa cas vypocita dynamicky
//this will be recalculated
params . isDusk = isDusk ;
params . isDawn = isDawn ;
//if(profile.astro_clock == true && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false)
if ( params . value == 0 )
{
params . info = "turn off line: " + line ;
if ( isDusk ) params . info = "dusk: turn off line: " + line ;
if ( isDawn ) params . info = "dawn: turn off line: " + line ;
}
else if ( params . value == 1 )
{
params . info = "turn on line: " + line ;
if ( isDusk ) params . info = "dusk: turn on line: " + line ;
if ( isDawn ) params . info = "dawn: turn on line: " + line ;
}
params . debug = true ;
//turn on/off line
tasks . push ( params ) ;
monitor . info ( params . info , start _time ) ;
}
monitor . info ( "-->time_points final" , line , time _points ) ;
//ensure to turn on/off according to calculated value
let params = getParams ( priorityTypes . terminal ) ;
params . type = "relay" ;
params . line = parseInt ( line ) ;
params . tbname = relaysData [ line ] . tbname ;
params . value = currentValue ;
params . isDusk = false ;
params . isDawn = false ;
params . timestamp = priorityTypes . terminal ;
params . addMinutesToTimestamp = 0 ;
params . debug = true ;
//logger.debug(now.toLocaleString("sk-SK"));
monitor . info ( "-->currentValue for relay" , line , currentValue ) ;
//turn on/off line
if ( params . value == 0 ) params . info = "turn off line on startup: " + line ;
else if ( params . value == 1 ) params . info = "turn on line on startup: " + line ;
tasks . push ( params ) ;
} catch ( error ) {
if ( profilestr !== "" )
{
//errLogger.error(profilestr, error);
errorHandler . sendMessageToService ( profilestr + "-" + error , 0 , "js_error" ) ;
}
}
}
//logger.debug("tasks:");
//logger.debug(tasks);
}
//PROCESS DEFAULT BROADCASTS
//RPC pre nody / broadcast
//Time of dusk, Time of dawn
//Actual Time
if ( processBroadcast )
{
let addMinutesToTimestamp = 5 ;
{
//run broadcast Time of dusk
2024-04-13 21:46:15 +02:00
addMinutesToTimestamp = 60 * 3 ;
2024-04-13 20:29:31 +02:00
let params = getParams ( priorityTypes . node _broadcast ) ;
let recipient = 2 ; //2 broadcast, address = 0
let address = 0 ; //0
if ( recipient === 2 )
{
address = 0xffffffff ; //Broadcast
}
let sunCalcResult = calculateDuskDown ( ) ;
let dusk _hours = sunCalcResult [ "dusk_hours" ] ;
let dusk _minutes = sunCalcResult [ "dusk_minutes" ] ;
params . address = address ; //broadcast
params . byte1 = dusk _hours ; //h
params . byte2 = dusk _minutes ; //m
params . byte3 = 0 ; //s
params . byte4 = 0 ;
params . recipient = recipient ;
params . register = 6 ; //Time of dusk - Reg 6
params . rw = 1 ; //write
let timestampStart = priorityTypes . node _broadcast ;
//other values
params . type = "cmd" ;
//params.tbname = tbname;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = addMinutesToTimestamp ;
params . info = "Broadcast-duskTime" ;
2024-04-13 21:46:15 +02:00
2024-04-13 20:29:31 +02:00
tasks . push ( params ) ;
}
{
//run broadcast Time of dawn
2024-04-13 21:46:15 +02:00
addMinutesToTimestamp = 60 * 3 ;
2024-04-13 20:29:31 +02:00
let params = getParams ( priorityTypes . node _broadcast ) ;
let recipient = 2 ; //2 broadcast, address = 0
let address = 0 ; //0
if ( recipient === 2 )
{
address = 0xffffffff ; //Broadcast
}
let sunCalcResult = calculateDuskDown ( ) ;
let dawn _hours = sunCalcResult [ "dawn_hours" ] ;
let dawn _minutes = sunCalcResult [ "dawn_minutes" ] ;
params . address = address ; //broadcast
params . byte1 = dawn _hours ; //h
params . byte2 = dawn _minutes ; //m
params . byte3 = 0 ; //s
params . byte4 = 0 ;
params . recipient = recipient ;
params . register = 7 ; //Time of dawn - Reg 6
params . rw = 1 ; //write
let timestampStart = priorityTypes . node _broadcast ;
//other values
params . type = "cmd" ;
//params.tbname = tbname;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = addMinutesToTimestamp ;
params . info = "Broadcast-dawnTime" ;
tasks . push ( params ) ;
}
{
//run broadcast //Actual time
addMinutesToTimestamp = 5 ;
let params = getParams ( priorityTypes . node _broadcast ) ;
let recipient = 2 ; //2 broadcast, address = 0
let address = 0 ; //0
if ( recipient === 2 )
{
address = 0xffffffff ; //Broadcast
}
var d = new Date ( ) ;
let hours = d . getHours ( ) ;
let minutes = d . getMinutes ( ) ;
let seconds = d . getSeconds ( ) ;
params . address = address ; //broadcast
params . byte1 = hours ; //h
params . byte2 = minutes ; //m
params . byte3 = seconds ; //s
params . byte4 = 0 ;
params . recipient = recipient ;
params . register = 87 ; //Actual time
params . rw = 1 ; //write
let timestampStart = priorityTypes . node _broadcast ;
//other values
params . type = "cmd" ;
//params.tbname = tbname;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = addMinutesToTimestamp ;
params . info = "run broadcast: Actual time" ;
tasks . push ( params ) ;
}
{
//run broadcast Actual Lux level from cabinet
//Do tohto registra posiela riadiaca jednotka hodnotu intenzity osvetlenia ktorú meria jej senzor pre potreby riadenia časov súmraku resp. úsvitu podľa intenzity osvetlenia.
//Byty 0 (LSB) a 1 obsahujú 16 bitový integer s luxami.
let params = getParams ( priorityTypes . node _broadcast ) ;
addMinutesToTimestamp = 15 ;
let recipient = 2 ; //2 broadcast, address = 0
let address = 0 ; //0
if ( recipient === 2 )
{
address = 0xffffffff ; //Broadcast
}
//TODO
//16 bitový integer s luxami
params . byte3 = lux _sensor ;
params . byte4 = lux _sensor ;
params . timestamp = priorityTypes . node _broadcast ;
params . addMinutesToTimestamp = addMinutesToTimestamp ;
params . info = "run broadcast: Actual Lux level from cabinet" ;
params . register = 95 ; //Actual Lux level from cabinet
params . rw = 1 ; //write
}
}
//process nodes & tasks
//reportovanie pre platformu
if ( processNodes )
{
for ( let k in nodesData ) {
let address = parseInt ( k ) ;
let tbname = nodesData [ k ] . tbname ;
let register = 0 ;
//logger.debug("generated cmd - buildTasks for node:", address);
//listOfCommands - READ
for ( let i = 0 ; i < listOfCommands . length ; i ++ )
{
register = listOfCommands [ i ] ;
let params = getParams ( priorityTypes . node _cmd ) ;
//core rpc values
params . address = address ;
params . byte1 = 0 ;
params . byte2 = 0 ;
params . byte3 = 0 ;
params . byte4 = 0 ;
params . recipient = 1 ;
params . register = register ;
params . rw = 0 ;
let addMinutesToTimestamp = priorities [ register ] ;
let timestampStart = priorityTypes . node _cmd ; //run imediatelly in function runTasks
if ( addMinutesToTimestamp > 1 )
{
timestampStart = timestampStart + addMinutesToTimestamp * 60000 ;
}
//other values
params . type = "cmd" ;
params . tbname = tbname ;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = addMinutesToTimestamp ;
params . info = "generated cmd - buildTasks (node)" ;
//monitor last node && last command
/ *
if ( register == listOfCommands [ listOfCommands . length - 1 ] )
{
//if(k == 632) params.debug = true;
if ( k == 698 ) params . debug = true ;
}
* /
tasks . push ( params ) ;
}
}
}
//niektore ulohy sa vygeneruju iba 1x pri starte!!!
if ( ! init ) return ;
//Priebežne (raz za cca 5 minút) je potrebné vyčítať z Master nodu verziu jeho FW.
//Jedná sa o register 10. Rovnaká interpretácia ako pri FW verzii nodu.
//Adresa mastera je 0. V prípade že kedykoľvek nastane situácia že Master Node neodpovedá (napríklad pri vyčítaní telemetrie z nodu nevráti žiadne dáta),
//tak treba vyreportovať string "NOK".
{
let params = getParams ( priorityTypes . fw _detection ) ;
params . type = "cmd" ;
params . register = 4 ;
params . address = 0 ;
let timestampStart = priorityTypes . fw _detection ;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = 5 ;
params . tbname = FLOW . OMS _edgeName ;
params . info = "Master node FW verzia" ;
//params.debug = true;
//this will set FLOW.OMS_masterNodeIsResponding
tasks . push ( params ) ;
}
//kazdu hodinu skontrolovat nastavenie profilov
{
let params = getParams ( priorityTypes . fw _detection ) ;
params . type = "process_profiles" ;
let timestampStart = priorityTypes . relay _profile ;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = 60 ; //60 = every hour
params . info = "detekcia nespracovaných profilov linie a nodov" ;
//params.debug = true;
tasks . push ( params ) ;
}
{
//edge_date_time
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "edge_date_time" ;
let timestampStart = priorityTypes . node _cmd ;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = 1 ;
params . tbname = FLOW . OMS _edgeName ;
params . info = "reportovanie aktuálneho času na LM - EDGE-Date Time" ;
//logger.debug("BUILD Master node FW verzia");
tasks . push ( params ) ;
}
{
//edge_date_time
let params = getParams ( priorityTypes . node _cmd ) ;
params . type = "number_of_luminaires" ;
let timestampStart = priorityTypes . node _cmd + 1 ;
params . timestamp = timestampStart ;
params . addMinutesToTimestamp = 1 ;
params . tbname = FLOW . OMS _edgeName ;
params . info = "reportovanie number_of_luminaires" ;
tasks . push ( params ) ;
}
monitor . info ( "tasks created:" , tasks . length ) ;
}
function turnOnOffLinesAccordingToLuxSensor ( lux _sensor _value )
{
//let dusk_hours = sunCalcResult["dusk_hours"];
//let dusk_minutes = sunCalcResult["dusk_minutes"];
let duskTimeStamp ;
let downTimeStamp ;
//prejedme si line s profilom, kde mame "astro_clock": true
/ *
"dawn_lux_sensor" : true ,
"dusk_lux_sensor" : true ,
"dawn_lux_sensor_value" : 5 ,
"dusk_lux_sensor_value" : 5 ,
"dawn_astro_clock_offset" : 0 ,
"dusk_astro_clock_offset" : 10 ,
"dawn_lux_sensor_time_window" : 30 ,
"dusk_lux_sensor_time_window" : 30 ,
"dawn_astro_clock_time_window" : 60 ,
"dusk_astro_clock_time_window" : 60
* /
//ak sme pred/po vychode a lux value <= lux_sensor_value, liniu zapneme
//ak sme pred/po zapade a lux_value <= lux_sensor_value, liniu zapneme
let now = new Date ( ) ;
let currentTimestamp = now . getTime ( ) ;
let keys = Object . keys ( relaysData ) ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let line = keys [ i ] ; //line is turned off by default
let profilestr = relaysData [ line ] . profile ;
try {
let profile = JSON . parse ( profilestr ) ;
if ( Object . keys ( profile ) . length === 0 ) throw ( "profile is not defined" ) ;
if ( profile . astro _clock == true )
{
2024-04-13 21:46:15 +02:00
let sunCalcResult = calculateDuskDown ( date , line ) ;
2024-04-13 20:29:31 +02:00
//dawn: usvit/vychod - lux je nad hranicou - vypnem
//dusk: zapad pod hranicou - zapnem
//"dawn_lux_sensor_time_window": 30,
//"dusk_lux_sensor_time_window": 30,
//vychod
if ( profile . dawn _lux _sensor == true )
{
2024-04-13 21:46:15 +02:00
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 ) ;
2024-04-13 20:29:31 +02:00
if ( currentTimestamp >= lux _sensor _time _window1 && currentTimestamp <= lux _sensor _time _window2 )
{
//dawn: usvit/vychod - lux je nad hranicou - vypnem
if ( lux _sensor _value > profile . dawn _lux _sensor _value )
{
//vypnem
2024-04-13 21:46:15 +02:00
turnOffLine ( line , "profile: dawn - turnOff line according to lux sensor" ) ;
}
else
{
//zapnem
turnOnLine ( line , "profile: dawn - turnOn line according to lux sensor" ) ;
2024-04-13 20:29:31 +02:00
}
}
//ak sme po vychode
if ( currentTimestamp > lux _sensor _time _window2 )
{
//vypneme
//urobime jednorazovy prikaz
}
}
//zapad
if ( profile . dusk _lux _sensor == true )
{
2024-04-13 21:46:15 +02:00
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 ) ;
2024-04-13 20:29:31 +02:00
if ( currentTimestamp >= lux _sensor _time _window1 && currentTimestamp <= lux _sensor _time _window2 )
{
//dusk: zapad pod hranicou - zapnem
if ( lux _sensor _value < profile . dusk _lux _sensor _value )
{
//zapnem
2024-04-13 21:46:15 +02:00
turnOnLine ( line , "profile: dusk - turnOff line according to lux sensor" ) ;
}
else
{
//vypnem
turnOffLine ( line , "profile: dusk - turnOff line according to lux sensor" ) ;
2024-04-13 20:29:31 +02:00
}
}
}
}
} catch ( error ) {
//if(profilestr !=="" ) logger.debug(profilestr, error);
}
}
}
let sunCalcResult = calculateDuskDown ( ) ;
let reportDuskDawn = {
dusk _time : sunCalcResult . dusk _time ,
dawn _time : sunCalcResult . dawn _time ,
dusk _time _reported : undefined ,
dawn _time _reported : undefined
} ;
async function upateNodeStatus ( node , status )
{
//MASTER
if ( node == 0 ) return ;
let nodeObj = nodesData [ node ] ;
if ( nodeObj == undefined ) return ;
if ( status )
{
cmdNOKNodeCounter [ node ] = 0 ;
}
else cmdNOKNodeCounter [ node ] ++ ;
if ( nodeObj . status !== status )
{
await dbNodes . modify ( { status : status } ) . where ( "node" , node ) . make ( function ( builder ) {
builder . callback ( function ( err , response ) {
if ( err == null ) nodesData [ node ] . status = status ;
} ) ;
} ) ;
}
}
2024-04-13 21:46:15 +02:00
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 )
} ) ;
} ) ;
}
}
2024-04-13 20:29:31 +02:00
async function runTasks ( ) {
clearInterval ( interval ) ;
let currentTimestamp = Date . now ( ) ;
//report dusk, dawn---------------------------------
if ( reportDuskDawn . dusk _time < currentTimestamp )
{
//vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
if ( ( currentTimestamp - reportDuskDawn . dusk _time ) < 60 * 1000 )
{
//reportovali sme?
if ( reportDuskDawn . dusk _time _reported != sunCalcResult . dusk _time )
{
sendNotification ( "CMD Manager: calculated Time of dusk" , FLOW . OMS _edgeName , "dusk_has_occured" , { value : sunCalcResult [ "dusk" ] } , "" , instanceSendTo . tb , instance ) ;
reportDuskDawn . dusk _time _reported = sunCalcResult . dusk _time ;
}
}
var nextDay = new Date ( ) ;
nextDay . setDate ( nextDay . getDate ( ) + 1 ) ;
sunCalcResult = calculateDuskDown ( nextDay ) ;
reportDuskDawn . dusk _time = sunCalcResult . dusk _time ;
}
if ( reportDuskDawn . dawn _time < currentTimestamp )
{
//vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
if ( ( currentTimestamp - reportDuskDawn . dawn _time ) < 60 * 1000 )
{
//reportovali sme?
if ( reportDuskDawn . dawn _time _reported != sunCalcResult . dawn _time )
{
sendNotification ( "CMD Manager: calculated Time of dawn" , FLOW . OMS _edgeName , "dawn_has_occured" , { value : sunCalcResult [ "dawn" ] } , "" , instanceSendTo . tb , instance ) ;
reportDuskDawn . dawn _time _reported = sunCalcResult . dawn _time ;
}
}
var nextDay = new Date ( ) ;
nextDay . setDate ( nextDay . getDate ( ) + 1 ) ;
sunCalcResult = calculateDuskDown ( nextDay ) ;
reportDuskDawn . dawn _time = sunCalcResult . dawn _time ;
}
//--------------------------------------------------------
//sort tasks
//tasks.sort((a,b) => a.timestamp - b.timestamp );
tasks . sort ( function ( a , b ) {
if ( a . timestamp <= currentTimestamp && b . timestamp <= currentTimestamp )
{
return a . priority - b . priority ;
}
return a . timestamp - b . timestamp ;
} ) ;
if ( tasks . length == 0 )
{
instance . send ( instanceSendTo . debug , "no tasks created" ) ;
interval = setInterval ( runTasks , longInterval ) ;
return ;
}
if ( ! rsPort . isOpen )
{
instance . send ( instanceSendTo . debug , "!rsPort.isOpen" ) ;
//await rsPort.open();
//continue
}
let currentTask = tasks [ 0 ] ;
if ( currentTask . debug )
{
//logger.debug("--->task to process", currentTask);
}
if ( currentTask . timestamp <= currentTimestamp )
{
let params = { ... tasks [ 0 ] } ;
if ( FLOW . OMS _maintenance _mode )
{
//allow terminal commands
if ( params . type == "cmd-terminal" ) ;
else
{
interval = setInterval ( runTasks , longInterval ) ;
return ;
}
}
let type = params . type ;
let tbname = params . tbname ;
let nodeKey = params . address ;
let useProfile = params . useProfile ;
if ( useProfile === undefined ) useProfile = true ;
let duskOffset = params . duskOffset ;
let dawnOffset = params . dawnOffset ;
let line = null ;
//rpc related
if ( nodesData [ nodeKey ] !== undefined ) line = nodesData [ nodeKey ] . line ;
if ( params . line !== undefined ) line = params . line ;
let repeatTask = false ;
if ( params . addMinutesToTimestamp > 0 ) repeatTask = true ;
if ( params . isDawn || params . isDusk ) repeatTask = true ;
if ( repeatTask )
{
if ( type == "cmd" )
{
//set next start time automatically
tasks [ 0 ] . timestamp = currentTimestamp + tasks [ 0 ] . addMinutesToTimestamp * 60000 ;
}
}
else
{
//terminal data...
tasks . shift ( ) ;
}
//custom tasks
if ( type == "number_of_luminaires" )
{
tasks [ 0 ] . timestamp = currentTimestamp + tasks [ 0 ] . addMinutesToTimestamp * 60000 ;
//treba reportovat node status
{
//number_of_luminaires
//number_of_ok_luminaires
//number_of_nok_luminaires
let keys = Object . keys ( nodesData ) ;
let number _of _luminaires = keys . length ;
let number _of _ok _luminaires = 0 ;
let number _of _nok _luminaires = 0 ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let key = keys [ i ] ;
let nodeObj = nodesData [ key ] ;
if ( nodeObj . tbname == undefined ) continue ;
if ( nodeObj . status ) number _of _ok _luminaires ++ ;
else number _of _nok _luminaires ++ ;
}
let values = {
number _of _luminaires : number _of _luminaires ,
number _of _ok _luminaires : number _of _ok _luminaires ,
number _of _nok _luminaires : number _of _nok _luminaires
} ;
let dataToTb = {
[ FLOW . OMS _edgeName ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
interval = setInterval ( runTasks , shortIterval ) ;
return ;
}
}
//kontrola nespracovanych profilov nodov
if ( type == "process_profiles" )
{
tasks [ 0 ] . timestamp = currentTimestamp + tasks [ 0 ] . addMinutesToTimestamp * 60000 ;
//select nespracovane nody
//node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean
//buildTasks({processLineProfiles: true, line: line});
/ *
let keys = Object . keys ( nodesData ) ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let node = keys [ i ] ;
let line = node . line ;
if ( node . processed ) continue ;
if ( relaysData [ line ] != undefined )
{
let relayStatus = relaysData [ line ] . contactor ;
if ( relayStatus == 1 )
{
//linia je zapnuta
//await loadRelaysData(flowdata.data.line);
}
}
}
* /
//vsetky linie kt. su zapnute, a spracuju sa nespracovane profily nodov
loadRelaysData ( ) ;
interval = setInterval ( runTasks , shortIterval ) ;
return ;
}
if ( type == "edge_date_time" )
{
//var d = new Date();
//let hours = addZeroBefore(d.getHours());
//let minutes = addZeroBefore(d.getMinutes());
//let seconds = addZeroBefore(d.getSeconds());
//let values = {"edge_date_time": `${hours}:${minutes}:${seconds}`};
let values = { "edge_date_time" : Date . now ( ) } ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
tasks [ 0 ] . timestamp = currentTimestamp + tasks [ 0 ] . addMinutesToTimestamp * 60000 ;
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
interval = setInterval ( runTasks , shortIterval ) ;
return ;
}
//relay
if ( type == "relay" )
{
//ak je dusk, alebo dawn, vypocitame si dynamicky nove values
if ( params . isDawn || params . isDusk )
{
let date = new Date ( ) ;
date . setDate ( date . getDate ( ) + 1 ) ; //next day
let sunCalcResult ;
if ( useProfile ) sunCalcResult = calculateDuskDown ( date , params . line ) ;
else
{
//do not use profile, line is there for undefined
sunCalcResult = calculateDuskDown ( date , undefined , duskOffset , dawnOffset ) ;
}
if ( params . isDawn )
{
tasks [ 0 ] . timestamp = sunCalcResult . dawn _time ;
}
if ( params . isDusk )
{
tasks [ 0 ] . timestamp = sunCalcResult . dusk _time ;
}
}
else
{
if ( tasks [ 0 ] . addMinutesToTimestamp == 0 ) ; // tasks.shift();
else tasks [ 0 ] . timestamp = currentTimestamp + tasks [ 0 ] . addMinutesToTimestamp * 60000 ;
}
let info ;
if ( useProfile ) info = "aplikovaný bod profilu" ;
else info = params . info ;
let message = "" ;
if ( params . value == 1 )
{
turnOnLine ( params . line , info ) ;
message = "on" ;
}
else if ( params . value == 0 )
{
turnOffLine ( params . line , info ) ;
message = "off" ;
}
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", instanceSendTo.tb, instance, null );
if ( useProfile ) sendNotification ( "CMD Manager: process cmd" , FLOW . OMS _edgeName , "switching_profile_point_applied_to_line" , { line : params . line , value : message } , "" , instanceSendTo . tb , instance ) ;
interval = setInterval ( runTasks , shortIterval ) ;
return ;
}
//zhodeny hlavny istic
let disconnected = false ;
//if(rotary_switch_state == "Off") disconnected = true;
//state_of_breaker[line] - alebo istic linie
if ( state _of _breaker . hasOwnProperty ( line ) )
{
//if(state_of_breaker[line] == "Off") disconnected = true;
}
//toto sa reportuje po prijati dat z di_do_controlera
if ( disconnected )
{
let values = { "status" : "OFFLINE" } ;
logger . debug ( "disconnected" , values ) ;
logger . debug ( "rotary_switch_state" , rotary _switch _state ) ;
logger . debug ( "state_of_breaker" , state _of _breaker [ line ] ) ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//report only once!
if ( ! disconnectedReport . hasOwnProperty ( tbname ) ) disconnectedReport [ tbname ] = false ;
if ( ! disconnectedReport [ tbname ] )
{
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
}
interval = setInterval ( runTasks , shortIterval ) ;
return ;
}
disconnectedReport [ tbname ] = false ;
//high_priority
if ( ! FLOW . OMS _masterNodeIsResponding )
{
//ak neodpoveda, nebudeme vykonavat ziadne commands, okrem cmd-terminal, a fw version
errorHandler . sendMessageToService ( "Master node is not responding" ) ;
let stop = true ;
if ( params . type == "cmd-terminal" ) stop = false ;
//fw version - register == 4
if ( params . type == "cmd" && params . register == 4 && params . address == 0 ) stop = false ;
if ( stop )
{
interval = setInterval ( runTasks , longInterval ) ;
return ;
}
}
let relayStatus = 1 ;
if ( relaysData [ line ] != undefined )
{
relayStatus = relaysData [ line ] . contactor ;
}
if ( line == 0 ) relayStatus = 0 ;
if ( params . type == "cmd-terminal" ) relayStatus = 1 ;
//check if rotary_switch_state == "Off"
if ( relayStatus == 0 )
{
//console.log("------------------------------------relayStatus", relayStatus, line);
let values = { "status" : "OFFLINE" } ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
interval = setInterval ( runTasks , shortIterval ) ;
return ;
}
if ( ! rsPort . isOpen )
{
interval = setInterval ( runTasks , longInterval ) ;
return ;
}
//RE-CALCULATE VALUES
//set actual time for broadcast
if ( params . register == 87 && params . recipient === 2 )
{
var d = new Date ( ) ;
let hours = d . getHours ( ) ;
let minutes = d . getMinutes ( ) ;
let seconds = d . getSeconds ( ) ;
params . byte1 = hours ; //h
params . byte2 = minutes ; //m
params . byte3 = seconds ; //s
params . byte4 = 0 ;
}
//set dusk/down for broadcast
2024-04-13 21:46:15 +02:00
2024-04-13 20:29:31 +02:00
//Time of dusk
if ( params . register == 6 && params . recipient === 2 )
{
if ( params . type != "cmd-terminal" )
{
let sunCalcResult = calculateDuskDown ( ) ;
let dusk _hours = sunCalcResult [ "dusk_hours" ] ;
let dusk _minutes = sunCalcResult [ "dusk_minutes" ] ;
params . byte1 = dusk _hours ; //h
params . byte2 = dusk _minutes ; //m
params . byte3 = 0 ; //s
params . byte4 = 0 ;
//TODO astrohodiny
let dusk = "Time of dusk: " + sunCalcResult [ "dusk" ] ;
//sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dusk, "", instanceSendTo.tb, instance, null );
}
}
//Time of dawn
if ( params . register == 7 && params . recipient === 2 )
{
if ( params . type != "cmd-terminal" )
{
let sunCalcResult = calculateDuskDown ( ) ;
let dawn _hours = sunCalcResult [ "dawn_hours" ] ;
let dawn _minutes = sunCalcResult [ "dawn_minutes" ] ;
params . byte1 = dawn _hours ; //h
params . byte2 = dawn _minutes ; //m
params . byte3 = 0 ; //s
params . byte4 = 0 ;
//TODO astrohodiny
let dawn = "Time of dawn: " + sunCalcResult [ "dawn" ] ;
//sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dawn, "", instanceSendTo.tb, instance, null );
}
}
//-----------------------
let register = params . register ;
instance . send ( instanceSendTo . debug , "address: " + params . address + " register:" + params . register + "type: " + params . type ) ;
var startTime , endTime ;
startTime = new Date ( ) ;
let resp = com _generic ( params . address , params . recipient , params . rw , params . register , params . name , params . byte1 , params . byte2 , params . byte3 , params . byte4 ) ;
let readBytes = 11 ;
//if broadcast WRITE - do not read
//if(params.recipient == 2) readBytes = 0;
//WRITE + BROADCAST = readBytes = 0;
// if(params.rw == 1 && params.recipient == 2) readBytes = 0;
if ( params . hasOwnProperty ( "debug" ) )
{
//console.log("--->readBytes", readBytes, params);
}
await writeData ( rsPort , resp , readBytes ) . then ( function ( data ) {
endTime = new Date ( ) ;
var timeDiff = endTime - startTime ;
//--1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data
//let bytes = data.slice(0);
let bytes = data ;
let dataBytes = data . slice ( 5 , 9 ) ;
let result = detectIfResponseIsValid ( bytes ) ;
let message = result . message ;
let type = result . type ;
let error = result . error ;
//ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
if ( params . debug != "generated cmd" )
{
//debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug, params);
}
if ( params . hasOwnProperty ( "debug" ) )
{
if ( params . debug )
{
console . log ( "detected response:" , result ) ;
logger . debug ( "writeData: done " + type + " duration: " + timeDiff + " type: " + params . debug , params , result ) ;
}
}
//debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug);
//debug("writeData done", type, "duration", timeDiff, "type", params.debug, result);
let tbname = params . tbname ;
let saveToTb = true ;
if ( tbname == null || tbname == undefined || tbname == "" ) saveToTb = false ;
//--
//CMD FINISHED
if ( message == "OK" )
{
upateNodeStatus ( params . address , true ) ;
//write
if ( params . type == "set_node_profile" )
{
let result = cmdCounterResolve ( params . address ) ;
if ( result == 0 )
{
dbNodes . modify ( { processed : true } ) . where ( "node" , params . address ) . make ( function ( builder ) {
builder . callback ( function ( err , response ) {
sendNotification ( "CMD Manager: process cmd" , FLOW . OMS _edgeName , "dimming_profile_was_successfully_received_by_node" , { node : params . address } , "" , instanceSendTo . tb , instance ) ;
logger . debug ( "--> profil úspešne odoslaný na node č. " + params . address ) ;
nodesData [ params . address ] . processed = true ;
} ) ;
} ) ;
}
}
2024-04-13 21:46:15 +02:00
// 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 ) ;
}
2024-04-13 20:29:31 +02:00
//parse read response
let values = { } ;
if ( params . rw == 0 ) {
values = processResponse ( register , dataBytes ) ; //read
2024-04-13 21:46:15 +02:00
// console.log('-------****', values);
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
2024-04-13 20:29:31 +02:00
if ( params . rw == 1 )
2024-04-13 21:46:15 +02:00
{
//write command
2024-04-13 20:29:31 +02:00
//set command dimming
2024-04-13 21:46:15 +02:00
if ( params . register == 1 )
{
values = { "comm_status" : message } ;
}
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
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 ;
}
2024-04-13 20:29:31 +02:00
if ( params . register == 0 ) values [ "status" ] = message ;
//fw version - register == 4
if ( params . register == 4 ) values [ "edge_fw_version" ] = FLOW . OMS _edge _fw _version ;
if ( params . address == 0 )
{
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", instanceSendTo.tb, instance, "rvo_status" );
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, "master_node_is_responding_again", {}, "", instanceSendTo.tb, instance, "rvo_status" );
sendNotification ( "CMD Manager: process cmd" , FLOW . OMS _edgeName , "master_node_is_responding_again" , { } , "" , instanceSendTo . tb , instance , "rvo_status" ) ;
FLOW . OMS _masterNodeIsResponding = true ;
}
//odoslanie príkazu z terminálu - dáta
if ( params . type == "cmd-terminal" )
{
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.DEBUG, "odoslanie príkazu z terminálu", params, instanceSendTo.tb, instance, null );
sendNotification ( "CMD Manager: process cmd" , FLOW . OMS _edgeName , "command_was_sent_from_terminal_interface" , { } , params , instanceSendTo . tb , instance ) ;
}
if ( params . debug )
{
logger . debug ( "saveToTb" , saveToTb , tbname , values ) ;
}
if ( saveToTb )
{
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
}
else
{
if ( params . type == "cmd-terminal" )
{
if ( params . refFlowdataKey != undefined )
{
logger . debug ( "cmd-terminal SUCCESS" ) ;
logger . debug ( currentTask ) ;
//make http response
let responseObj = { } ;
responseObj [ "type" ] = "SUCESS" ;
responseObj [ "bytes" ] = data ;
//params.refFlowdata.data = responseObj;
//instance.send(instanceSendTo.http_response, params.refFlowdata);
let refFlowdata = refFlowdataObj [ params . refFlowdataKey ] ;
refFlowdata . data = responseObj ;
instance . send ( instanceSendTo . http _response , refFlowdata ) ;
}
else
{
console . log ( "params.refFlowdataKey is undefined" , params ) ;
}
}
}
}
else
{
upateNodeStatus ( params . address , false ) ;
if ( params . refFlowdataKey != undefined )
{
logger . debug ( "cmd-terminal FAILED" ) ;
logger . debug ( currentTask ) ;
//make http response
let responseObj = { } ;
responseObj [ "type" ] = "ERROR" ;
responseObj [ "bytes" ] = data ;
//params.refFlowdata.data = responseObj;
//instance.send(instanceSendTo.http_response, params.refFlowdata);
let refFlowdata = refFlowdataObj [ params . refFlowdataKey ] ;
if ( refFlowdata !== undefined )
{
refFlowdata . data = responseObj ;
instance . send ( instanceSendTo . http _response , refFlowdata ) ;
}
}
/ *
if ( params . type == "cmd-terminal" )
{
if ( params . refFlowdata != undefined )
{
logger . debug ( "cmd-terminal FAILED" ) ;
logger . debug ( currentTask ) ;
//make http response
let responseObj = { } ;
responseObj [ "type" ] = "ERROR" ;
responseObj [ "bytes" ] = data ;
params . refFlowdata . data = responseObj ;
instance . send ( instanceSendTo . http _response , params . refFlowdata ) ;
}
}
* /
if ( params . address == 0 )
{
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", instanceSendTo.tb, instance, "rvo_status");
sendNotification ( "CMD Manager: process cmd" , FLOW . OMS _edgeName , "master_node_is_not_responding" , { } , "" , instanceSendTo . tb , instance , "rvo_status" ) ;
logger . debug ( "master_node_is_not_responding" , params ) ;
FLOW . OMS _masterNodeIsResponding = false ;
}
if ( params . type == "set_node_profile" )
{
delete cmdCounter [ params . address ] ;
let tbname = nodesData [ params . address ] . tbname ;
2024-04-13 21:46:15 +02:00
//! LOG SPRACOVANIA PROFILU
//logger.debug( "profil nebol úspešne odoslaný na node č. ", params, result, resp);
2024-04-13 20:29:31 +02:00
//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 ) ;
}
//is it node?
if ( nodesData . hasOwnProperty ( params . address ) )
{
if ( cmdNOKNodeCounter [ params . address ] < 5 ) saveToTb = false ;
}
//Master node version
//if(params.register == 4 && saveToTb)
if ( saveToTb )
{
let values = {
"status" : "NOK"
} ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
}
//instance.send(instanceSendTo.debug, result);
if ( params . hasOwnProperty ( "debug" ) )
{
if ( params . debug )
{
logger . debug ( "writeData err: " , error , result , params ) ;
}
}
//logger.debug(error, result, params);
}
} ) . catch ( function ( reason ) {
console . log ( "writeData catch exception" , reason ) ;
logger . debug ( currentTask ) ;
if ( params . refFlowdataKey != undefined )
{
logger . debug ( "catch: cmd-terminal FAILED" ) ;
logger . debug ( currentTask ) ;
//make http response
let responseObj = { } ;
responseObj [ "type" ] = "ERROR" ; //
responseObj [ "message" ] = "ERROR WRITE FAILED: " + reason ; //
//params.refFlowdata.data = responseObj;
//instance.send(instanceSendTo.http_response, params.refFlowdata);
let refFlowdata = refFlowdataObj [ params . refFlowdataKey ] ;
if ( refFlowdata !== undefined )
{
refFlowdata . data = responseObj ;
instance . send ( instanceSendTo . http _response , refFlowdata ) ;
}
}
/ *
if ( params . type == "cmd-terminal" )
{
if ( params . refFlowdata != undefined )
{
logger . debug ( "cmd-terminal FAILED" ) ;
logger . debug ( currentTask ) ;
//make http response
let responseObj = { } ;
responseObj [ "type" ] = "ERROR WRITE FAILED: " + reason ;
//responseObj["bytes"] = data;
params . refFlowdata . data = responseObj ;
instance . send ( instanceSendTo . http _response , params . refFlowdata ) ;
//refFlowdata = undefined;
}
}
* /
if ( params . hasOwnProperty ( "debug" ) )
{
if ( params . debug )
{
logger . debug ( "-->WRITE FAILED: " + reason , params . debug , params ) ;
}
}
upateNodeStatus ( params . address , false ) ;
let tbname = params . tbname ;
let saveToTb = true ;
if ( tbname == null || tbname == undefined || tbname == "" ) saveToTb = false ;
if ( params . address == 0 )
{
//sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", instanceSendTo.tb, instance, "rvo_status");
sendNotification ( "CMD Manager: process cmd" , FLOW . OMS _edgeName , "master_node_is_not_responding" , { } , "" , instanceSendTo . tb , instance , "rvo_status" ) ;
logger . debug ( "master_node_is_not_responding" , params ) ;
FLOW . OMS _masterNodeIsResponding = false ;
}
if ( params . type == "set_node_profile" )
{
delete cmdCounter [ params . address ] ;
let tbname = nodesData [ params . address ] . tbname ;
logger . debug ( "profil nebol úspešne odoslaný na node č. " , params , resp ) ;
//sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "odosielanie profilu na node č. " + params.address + " zlyhalo", "", instanceSendTo.tb, instance, null );
sendNotification ( "CMD Manager: process cmd" , tbname , "configuration_of_dimming_profile_to_node_failed" , { node : params . address } , "" , instanceSendTo . tb , instance ) ;
}
//is it node?
if ( nodesData . hasOwnProperty ( params . address ) )
{
if ( cmdNOKNodeCounter [ params . address ] < 5 ) saveToTb = false ;
}
//Master node version
if ( params . register == 4 && saveToTb )
{
let values = {
"status" : "NOK" ,
"master_node_version" : "NOK"
} ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
FLOW . OMS _masterNodeIsResponding = false ;
}
//treba?
/ *
else if ( saveToTb )
{
let values = {
"comm_status" : "no_comm"
} ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
}
instance . send ( instanceSendTo . tb , dataToTb ) ;
}
* /
instance . send ( instanceSendTo . debug , reason ) ;
} ) ;
}
else
{
if ( currentTask . debug )
{
//currentTask.timestamp <= currentTimestamp
logger . debug ( "currentTask is not processed - task is in the future" , currentTask ) ;
}
interval = setInterval ( runTasks , longInterval ) ;
return ;
}
//console.log("----->runTasks - setInterval", new Date());
interval = setInterval ( runTasks , shortIterval ) ;
}
//! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
2024-04-13 21:46:15 +02:00
// const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
// const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
2024-04-13 20:29:31 +02:00
if ( FLOW . OMS _serial _port == "" ) FLOW . OMS _serial _port = "ttymxc4" ;
if ( FLOW . OMS _serial _port == undefined ) FLOW . OMS _serial _port = "ttymxc4" ;
if ( FLOW . OMS _serial _port . length === 1 ) FLOW . OMS _serial _port = "ttymxc4" ;
2024-04-13 21:46:15 +02:00
const rsPort = new SerialPort ( ` /dev/ ${ FLOW . OMS _serial _port } ` , { autoOpen : false } ) ;
2024-04-13 20:29:31 +02:00
//(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
//rsPort.setMaxListeners(0);
2024-04-13 21:46:15 +02:00
rsPort . on ( 'open' , async function ( ) {
2024-04-13 20:29:31 +02:00
logger . debug ( "CMD manager - rsPort opened sucess" ) ;
await loadRelaysData ( ) ;
2024-04-13 21:46:15 +02:00
await runSyncExec ( ` stty -F /dev/ ${ FLOW . OMS _serial _port } 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke ` ) . then ( function ( status ) {
2024-04-13 20:29:31 +02:00
instance . send ( instanceSendTo . debug , "RPC runSyncExec - Promise Resolved:" + status ) ;
logger . debug ( 0 , "RPC runSyncExec - Promise Resolved:" + status ) ;
//APP START
let dataToInfoSender = { id : FLOW . OMS _projects _id , name : FLOW . OMS _rvo _name } ;
dataToInfoSender . fw _version = FLOW . OMS _edge _fw _version ;
dataToInfoSender . startdate = new Date ( ) . toISOString ( ) . slice ( 0 , 19 ) . replace ( 'T' , ' ' ) ;
dataToInfoSender . _ _force _ _ = true ;
instance . send ( instanceSendTo . infoSender , dataToInfoSender ) ;
logger . debug ( 0 , "---------------------------->START message send to service" , dataToInfoSender ) ;
//----
nodesData = { } ;
dbNodes . find ( ) . make ( function ( builder ) {
builder . callback ( function ( err , response ) {
for ( let i = 0 ; i < response . length ; i ++ )
{
let node = response [ i ] ;
let key = node [ "node" ] ;
nodesData [ key ] = node ;
}
//buildTasks();
//interval = setInterval(runTasks, longInterval);
// console.log('******** nodesData',nodesData);
} ) ;
} ) ;
2024-04-13 21:46:15 +02:00
} ) . catch ( function ( reason ) {
instance . send ( instanceSendTo . debug , "CMD manager - RPC runSyncExec - promise rejected:" + reason ) ;
} ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
} ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
rsPort . on ( 'error' , function ( err ) {
2024-04-13 20:29:31 +02:00
//TODO report to service!!!
//errLogger.error(exports.title, "unable to open port", FLOW.OMS_serial_port, err.message);
errorHandler . sendMessageToService ( [ exports . title , "unable to open port" , FLOW . OMS _serial _port , err . message ] , 0 ) ;
2024-04-13 21:46:15 +02:00
instance . send ( instanceSendTo . debug , err . message ) ;
2024-04-13 20:29:31 +02:00
} ) ;
2024-04-13 21:46:15 +02:00
rsPort . on ( "close" , ( ) => {
rsPort . close ( ) ;
} ) ;
2024-04-13 20:29:31 +02:00
//loadRelaysData();
rsPort . open ( ) ;
2024-04-13 21:46:15 +02:00
instance . on ( "close" , ( ) => {
2024-04-13 20:29:31 +02:00
clearInterval ( interval ) ;
2024-04-13 21:46:15 +02:00
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 ;
}
2024-04-13 20:29:31 +02:00
//onData
instance . on ( "data" , async function ( flowdata ) {
2024-04-13 21:46:15 +02:00
//instance.on("data", (data) => {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//instance.send(instanceSendTo.debug, "on Data");
//instance.send(instanceSendTo.debug, flowdata);
//logger.debug(flowdata.data);
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//just testing functions
if ( flowdata . data == "open" )
{
if ( ! rsPort . isOpen ) rsPort . open ( ) ;
return ;
}
else if ( flowdata . data == "close" )
{
rsPort . close ( ) ;
return ;
}
else if ( flowdata . data == "clean" )
{
tasks = [ ] ;
return ;
}
else if ( flowdata . data == "buildtasks" )
{
//build & run
return ;
}
else if ( flowdata . data == "run" )
{
//durations = [];
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( tasks . length == 0 )
{
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
buildTasks ( ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( rsPort . isOpen )
{
interval = setInterval ( runTasks , 100 ) ;
}
else
{
instance . send ( instanceSendTo . debug , "port is not opened!!!" ) ;
2024-04-13 20:29:31 +02:00
}
}
2024-04-13 21:46:15 +02:00
}
else
{
//terminal data - object
//logger.debug("flowdata", flowdata.data);
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( typeof flowdata . data === 'object' )
{
//logger.debug("dido", flowdata.data);
if ( flowdata . data . hasOwnProperty ( "sender" ) )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
//data from di_do_controller
if ( flowdata . data . sender == "di_do_controller" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
if ( flowdata . data . hasOwnProperty ( "cmd" ) )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
let cmd = flowdata . data . cmd ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( cmd == "buildTasks" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
clearInterval ( interval ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
logger . debug ( "-->CMD MANAGER - BUILD TASKS" ) ;
buildTasks ( ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//logger.debug("tasks:");
//logger.debug(tasks);
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
logger . debug ( "-->CMD MANAGER - RUN TASKS" ) ;
interval = setInterval ( runTasks , longInterval ) ;
}
else if ( cmd == "reload_relays" )
{
await loadRelaysData ( flowdata . data . line ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( flowdata . data . dataChanged )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
if ( ! flowdata . data . value )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
reportOfflineNodeStatus ( flowdata . data . line ) ;
}
else
{
reportOnlineNodeStatus ( flowdata . data . line ) ;
2024-04-13 20:29:31 +02:00
}
}
2024-04-13 21:46:15 +02:00
}
else if ( cmd == "rotary_switch_state" )
{
//state was changed
if ( rotary _switch _state != flowdata . data . value )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
if ( rotary _switch _state == "Off" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
//vyreportovat vsetky svietdla
reportOfflineNodeStatus ( ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
else reportOnlineNodeStatus ( ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
rotary _switch _state = flowdata . data . value ;
}
else if ( cmd == "lux_sensor" )
{
lux _sensor = parseInt ( flowdata . data . value ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//process profiles
turnOnOffLinesAccordingToLuxSensor ( lux _sensor ) ;
}
else if ( cmd == "state_of_breaker" )
{
//istic linie
let value = flowdata . data . value ;
let line = parseInt ( flowdata . data . line ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let dataChanged = false ;
if ( state _of _breaker [ line ] != value ) dataChanged = true ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
state _of _breaker [ line ] = value ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let status = "OK" ;
let weight = ERRWEIGHT . NOTICE ;
let message = ` zapnutý istič línie č. ${ line } ` ;
if ( value == "Off" )
{
weight = ERRWEIGHT . ERROR ;
message = ` vypnutý istič línie č. ${ line } ` ;
status = "NOK" ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( dataChanged ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( relaysData . hasOwnProperty ( line ) )
{
let tbname = relaysData [ line ] . tbname ;
if ( value == "Off" ) sendNotification ( "CMD Manager: onData" , tbname , "circuit_breaker_was_turned_off_line" , { line : line } , "" , instanceSendTo . tb , instance , "circuit_breaker" ) ;
else sendNotification ( "CMD Manager: onData" , tbname , "circuit_breaker_was_turned_on_line" , { line : line } , "" , instanceSendTo . tb , instance , "circuit_breaker" ) ;
//report status liniu
let values = {
"status" : status
} ;
let dataToTb = {
[ tbname ] : [
{
"ts" : Date . now ( ) ,
"values" : values
}
]
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
//instance.send(instanceSendTo.tb, dataToTb);
tbHandler . sendToTb ( dataToTb , instance ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//current value
if ( value == "Off" )
{
//vyreportovat vsetky svietdla na linii
reportOfflineNodeStatus ( line ) ;
}
else reportOnlineNodeStatus ( line ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
}
else {
logger . debug ( "undefined cmd" , cmd ) ;
2024-04-13 20:29:31 +02:00
}
}
}
2024-04-13 21:46:15 +02:00
return ;
}
//data from worksys
if ( flowdata . data . hasOwnProperty ( "topic" ) )
{
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let data = flowdata . data . content . data ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let command = data . params . command ;
let method = data . method ;
let profile = data . params . payload ;
if ( profile == undefined ) profile = "" ;
let entity = data . params . entities [ 0 ] ;
let entity _type = entity . entity _type ;
let tbname = entity . tb _name ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
instance . send ( instanceSendTo . debug , flowdata . data ) ;
logger . debug ( "--->worksys" , flowdata . data , data . params , entity , entity _type , command , method ) ;
logger . debug ( "----------------------------" ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
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" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
//let command = data.params.command;
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 )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
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" )
{
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let params = getParams ( priorityTypes . high _priority ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
value = parseInt ( value ) ;
if ( value > 0 ) value = value + 128 ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//set dimming - LUM1_13 - 647 je node linie 1 kt. dobre vidime
params . type = "cmd" ;
params . tbname = tbname ;
params . address = node ;
params . register = 1 ; //dimming
params . recipient = 1 ; //slave
params . byte4 = value ;
params . rw = 1 ; //write
params . timestamp = priorityTypes . high _priority ;
params . info = 'setNodeDimming' ;
//params.debug = true;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//ak linia je
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//debug(params);
logger . debug ( "dimming" , params ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
tasks . push ( params ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
updateNodeDimming ( node , value ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
setTimeout ( function ( ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//spustime o 4 sekundy neskor, s prioritou priorityTypes.high_priority
//a pridame aj vyreportovanie dimmingu
{
let params = getParams ( priorityTypes . high _priority ) ;
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 = 'read dimming (after set dimming from platform)' ;
params . debug = true ;
tasks . push ( params ) ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//pridame aj vyreportovanie - vykon
{
let params = getParams ( priorityTypes . high _priority ) ;
params . type = "cmd" ;
params . tbname = tbname ;
params . address = node ;
params . register = 76 ;
params . recipient = 1 ; //slave
params . rw = 0 ; //read
params . timestamp = priorityTypes . high _priority ;
params . info = 'read Input Power (after set dimming from platform)' ;
params . debug = true ;
tasks . push ( params ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
//pridame aj vyreportovanie - prud svietidla
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
let params = getParams ( priorityTypes . high _priority ) ;
params . type = "cmd" ;
params . tbname = tbname ;
params . address = node ;
params . register = 75 ;
params . recipient = 1 ; //slave
params . rw = 0 ; //read
params . timestamp = priorityTypes . high _priority ;
params . info = 'read Input Current (after set dimming from platform)' ;
params . debug = true ;
tasks . push ( params ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
//pridame aj vyreportovanie - power faktor - ucinnik
{
let params = getParams ( priorityTypes . high _priority ) ;
params . type = "cmd" ;
params . tbname = tbname ;
params . address = node ;
params . register = 77 ;
params . recipient = 1 ; //slave
params . rw = 0 ; //read
params . timestamp = priorityTypes . high _priority ;
params . info = 'read power factor - Cos phi (after set dimming from platform)' ;
params . debug = true ;
tasks . push ( params ) ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
} , 5000 ) ;
}
else if ( command === "cct" )
{
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 ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
else if ( command == "timeout" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
let params = getParams ( priorityTypes . high _priority ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
value = parseInt ( value ) ;
byte3 = Math . floor ( value / 256 ) ;
byte4 = value - ( byte3 * 256 ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
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 ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
console . log ( '-------- SetNodeTimeout queued in tasks' ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
tasks . push ( params ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
setTimeout ( function ( ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
// vyreportujeme nodeTimeoutMovement na platformu
let params = getParams ( priorityTypes . high _priority ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
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 ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
else if ( command == "dimming_no_mov" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
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 ) ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
return ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
else if ( method == "set_profile" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
//nastav profil nodu
logger . debug ( "-->set_profile for node" , data . params ) ;
logger . debug ( "------profile data" , profile ) ;
//instance.send(instanceSendTo.debug, "set_profile" + command);
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let keys = Object . keys ( nodesData ) ;
for ( let i = 0 ; i < keys . length ; i ++ )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
let node = keys [ i ] ;
if ( tbname == nodesData [ node ] . tbname . trim ( ) )
{
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
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 ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
}
else
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
profile = JSON . stringify ( profile ) ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
dbNodes . modify ( { processed : false , profile : profile } ) . where ( "node" , node ) . make ( function ( builder ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
builder . callback ( function ( err , response ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
logger . debug ( "worksys - update node profile done" , profile ) ;
if ( profile === "" ) logger . debug ( "worksys - update node profile done - profile is empty" ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//profil úspešne prijatý pre node č. xx
//sendNotification("CMD manager", tbname, ERRWEIGHT.INFO, `profil úspešne poslaný z platformy na RVO pre node č. ${node}`, profile, instanceSendTo.tb, instance, null );
sendNotification ( "CMD manager" , tbname , "dimming_profile_was_processed_for_node" , { node : node } , profile , instanceSendTo . tb , instance ) ;
nodesData [ node ] . processed = false ;
nodesData [ node ] . profile = profile ;
let line = nodesData [ node ] . line ;
processNodeProfile ( node ) ;
} ) ;
} ) ;
2024-04-13 20:29:31 +02:00
}
}
2024-04-13 21:46:15 +02:00
}
else
{
instance . send ( instanceSendTo . debug , "unknown method " + method ) ;
logger . debug ( "unknown method" , method ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
return ;
}
}
//nastav profil linie z platformy
else if ( entity _type == "edb_line" || entity _type == "edb" || entity _type == "edb_line_ver4" )
{
//profil linie
//relays.table line:number|tbname:string|contactor:number|profile:string
//najdeme line relaysData
if ( method == "set_profile" )
{
logger . debug ( "-->set_profile for line" , data . params ) ;
logger . debug ( "profile data:" , profile ) ;
let keys = Object . keys ( relaysData ) ;
for ( let i = 0 ; i < keys . length ; i ++ )
{
let line = keys [ i ] ;
if ( tbname == relaysData [ line ] . tbname )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
//zmazeme tasky
removeTask ( { type : "relay" , line : line } ) ;
if ( profile != "" ) profile = JSON . stringify ( profile ) ;
dbRelays . modify ( { profile : profile } ) . where ( "line" , line ) . make ( function ( builder ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
builder . callback ( function ( err , response ) {
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//update profile
logger . debug ( "worksys - update relay profile done:" , profile ) ;
instance . send ( instanceSendTo . debug , "worksys - update relay profile done" ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
loadRelaysData ( line ) . then ( function ( data ) {
logger . debug ( "loadRelaysData DONE for line" , line ) ;
buildTasks ( { processLineProfiles : true , line : line } ) ;
} ) ;
sendNotification ( "CMD manager - set profile from worksys" , tbname , "switching_profile_was_processed_for_line" , { line : line } , profile , instanceSendTo . tb , instance ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
} ) ;
} ) ;
break ;
}
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
}
else if ( method == "set_command" )
{
let value = data . params . payload . value ;
if ( command === "switch" )
2024-04-13 20:29:31 +02:00
{
2024-04-13 21:46:15 +02:00
// if we receive rpc from platform, to switch maintenance mode, we set OMS_maintenance_mode flow variable to value;
if ( entity _type === "edb" || entity _type === "edb_ver4_se" ) FLOW . variables . OMS _maintenance _mode = value ;
let responseRelays = await promisifyBuilder ( dbRelays . find ( ) . where ( "tbname" , tbname ) ) ;
let line = 0 ;
if ( responseRelays . length == 1 ) line = responseRelays [ 0 ] . line ;
if ( value == false ) turnOffLine ( line , "command received form platform" ) ;
else turnOnLine ( line , "command received form platform" ) ;
}
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
else
{
instance . send ( instanceSendTo . debug , "undefined method " + method ) ;
logger . debug ( "undefined method" , method ) ;
2024-04-13 20:29:31 +02:00
}
return ;
2024-04-13 21:46:15 +02:00
}
else {
instance . send ( instanceSendTo . debug , "UNKNOW entity_type " + entity _type ) ;
logger . debug ( "UNKNOW entity_type" , entity _type ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
return ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//terminal
if ( ! rsPort . isOpen ) await rsPort . open ( ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let params = flowdata . data . body ;
if ( params == undefined )
{
//logger.debug("CMD manager flowdata.data.body is undefined");
return ;
}
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
params . priority = priorityTypes . terminal ;
params . type = "cmd-terminal" ;
params . tbname = "" ;
params . timestamp = priorityTypes . terminal ;
params . addMinutesToTimestamp = 0 ; // do not repeat task!!!
params . debug = true ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
let timestamp = Date . now ( ) ;
params . refFlowdataKey = timestamp ;
//params.refFlowdata = flowdata;
//refFlowdata = flowdata;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//console.log("flowdata", flowdata);
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
cleanUpRefFlowdataObj ( ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
refFlowdataObj [ timestamp ] = flowdata ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//fix
//params.address = params.adress;
logger . debug ( "received from terminal" , params ) ;
logger . debug ( "date/time:" , new Date ( ) ) ;
logger . debug ( "tasks length:" , tasks . length ) ;
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
//tasks = [];
//add to tasks
tasks . push ( params ) ;
2024-04-13 20:29:31 +02:00
}
2024-04-13 21:46:15 +02:00
}
} )
} // end of exports.install = function(instance)
2024-04-13 20:29:31 +02:00
/ * *
* setCorrectTime function runs once per hour
* If it is 3 o ' clock , it sets actual time , which is got from services
* https : //service-prod01.worksys.io/gettime
* If also detects Read Only Filesystem once a day
* /
function setCorrectPlcTimeOnceADay ( )
{
const currentTime = new Date ( ) ;
if ( currentTime . getHours ( ) != 3 ) return ;
RESTBuilder . make ( function ( builder ) {
if ( ! builder ) return ;
builder . method ( 'GET' ) ;
builder . url ( 'http://192.168.252.2:8004/gettime?projects_id=1' ) ;
builder . callback ( function ( err , response , output ) {
if ( err ) {
console . log ( err ) ;
return ;
}
const res = output . response ;
try {
const obj = JSON . parse ( res ) ;
let d = new Date ( obj . date ) ;
const now = new Date ( ) ;
let diffInMinutes = now . getTimezoneOffset ( ) ;
console . log ( "---->TimezoneOffset" , diffInMinutes ) ;
if ( d instanceof Date )
{
// monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
let year = d . getFullYear ( ) ;
let month = addZeroBefore ( d . getMonth ( ) + 1 ) ;
let day = addZeroBefore ( d . getDate ( ) ) ;
let hours = addZeroBefore ( d . getHours ( ) ) ;
let minutes = addZeroBefore ( d . getMinutes ( ) ) ;
let seconds = addZeroBefore ( d . getSeconds ( ) ) ;
let dateStr = ` ${ year } - ${ month } - ${ day } ${ hours } : ${ minutes } : ${ seconds } ` ;
exec ( ` sudo timedatectl set-time " ${ dateStr } " ` , ( err , stdout , stderr ) => {
if ( err || stderr ) {
console . error ( err ) ;
console . log ( stderr ) ;
console . log ( dateStr ) ;
monitor . info ( "failed timedatectl set-time" , err , stderr ) ;
}
else
{
monitor . info ( "setCorrectPlcTimeOnceADay() --> Nastaveny cas na: " , dateStr ) ;
}
} ) ;
}
} catch ( error ) {
logger . debug ( "setCorrectPlcTimeOnceADay - function error" , error , res ) ;
monitor . info ( "setCorrectPlcTimeOnceADay - function error" , error , res ) ;
}
// we detect readOnlyFileSystem once an hour as well
detectReadOnlyFilesystem ( ) ;
} ) ;
} ) ;
}
function detectReadOnlyFilesystem ( )
{
exec ( ` sudo egrep " ro,|,ro " /proc/mounts ` , ( err , stdout , stderr ) => {
if ( err || stderr ) {
console . error ( err ) ;
console . log ( stderr ) ;
} else {
//console.log("Read-only", stdout);
let lines = stdout + "" ;
lines = lines . split ( "\n" ) ;
let readOnlyDetected = "" ;
for ( let i = 0 ; i < lines . length ; i ++ )
{
if ( lines [ i ] . startsWith ( "/dev/mmcblk0p2" ) )
{
readOnlyDetected = lines [ i ] ;
}
}
if ( readOnlyDetected !== "" )
{
errorHandler . sendMessageToService ( "Detected: Read-only file system: " + readOnlyDetected ) ;
monitor . info ( "Read only filesystem detected" ) ;
}
}
} ) ;
}
let setCorrectTime = setInterval ( setCorrectPlcTimeOnceADay , 60000 * 60 ) ; // 1 hour
setCorrectPlcTimeOnceADay ( ) ;
2024-04-13 21:46:15 +02:00
2024-04-13 20:29:31 +02:00
///helper functions
function calculateDuskDown ( date , line , duskOffset = 0 , dawnOffset = 0 )
{
if ( date === undefined ) date = new Date ( ) ;
//if(duskOffset === undefined) duskOffset = 0;
//if(dawnOffset === undefined) dawnOffset = 0;
//let line = keys[i];
let profilestr = "" ;
if ( relaysData [ line ] != undefined ) profilestr = relaysData [ line ] . profile ;
let result = { } ;
var times = SunCalc . getTimes ( date , latitude , longitude ) ;
let dawn = new Date ( times . sunrise ) ; //usvit
let dusk = new Date ( times . sunset ) ; //sumrak
//http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
//https://mapa.zoznam.sk/zisti-gps-suradnice-m6
let dusk _astro _clock _offset = duskOffset ; //minutes
let dawn _astro _clock _offset = dawnOffset ; //minutes
try {
let profile = JSON . parse ( profilestr ) ;
if ( Object . keys ( profile ) . length === 0 ) throw ( "profile is not defined" ) ;
//Jednoduchý režim
if ( profile . astro _clock == false && profile . dusk _lux _sensor == false && profile . dawn _lux _sensor == false )
{
}
//Režim astrohodín
if ( profile . astro _clock == true )
{
//if(profile.dusk_lux_sensor == false)
{
if ( profile . hasOwnProperty ( "dusk_astro_clock_offset" ) ) dusk _astro _clock _offset = parseInt ( profile . dusk _astro _clock _offset ) ;
}
//if(profile.dawn_lux_sensor == false)
{
if ( profile . hasOwnProperty ( "dawn_astro_clock_offset" ) ) dawn _astro _clock _offset = parseInt ( profile . dawn _astro _clock _offset ) ;
}
}
//dusk - súmrak
//down, sunrise - svitanie
} catch ( error ) {
if ( profilestr != "" )
{
logger . debug ( profilestr ) ;
logger . debug ( error ) ;
}
}
result . dusk _no _offset = addZeroBefore ( dusk . getHours ( ) ) + ":" + addZeroBefore ( dusk . getMinutes ( ) ) ;
result . dawn _no _offset = addZeroBefore ( dawn . getHours ( ) ) + ":" + addZeroBefore ( dawn . getMinutes ( ) ) ;
dusk = new Date ( dusk . getTime ( ) + gmtOffset + dusk _astro _clock _offset * 60000 ) ;
dawn = new Date ( dawn . getTime ( ) + gmtOffset + dawn _astro _clock _offset * 60000 ) ;
result . dusk = addZeroBefore ( dusk . getHours ( ) ) + ":" + addZeroBefore ( dusk . getMinutes ( ) ) ;
result . dusk _hours = dusk . getHours ( ) ;
result . dusk _minutes = dusk . getMinutes ( ) ;
result . dawn = addZeroBefore ( dawn . getHours ( ) ) + ":" + addZeroBefore ( dawn . getMinutes ( ) ) ;
result . dawn _hours = dawn . getHours ( ) ;
result . dawn _minutes = dawn . getMinutes ( ) ;
result . dusk _time = dusk . getTime ( ) ;
result . dawn _time = dawn . getTime ( ) ;
result . dusk _astro _clock _offset = dusk _astro _clock _offset ;
result . dawn _astro _clock _offset = dawn _astro _clock _offset ;
return result ;
}
function processResponse ( register , bytes )
{
let values = { } ;
let byte3 = bytes [ 0 ] ;
let byte2 = bytes [ 1 ] ;
let byte1 = bytes [ 2 ] ;
let byte0 = bytes [ 3 ] ;
//status
if ( register == 0 )
{
let statecode = bytesToInt ( bytes ) ;
values = { "statecode" : statecode } ;
return values ;
}
//Dimming, CCT
if ( register == 1 )
{
let brightness = 0 ;
let dimming = byte0 ;
if ( dimming > 128 ) {
brightness = dimming - 128 ;
}
2024-04-13 21:46:15 +02:00
values [ "dimming" ] = brightness ;
2024-04-13 20:29:31 +02:00
let cct ;
2024-04-13 21:46:15 +02:00
if ( byte3 == 1 ) cct = ( byte2 * 256 ) + byte1 ;
//else cct = bytesToInt(bytes.slice(0, 3));
2024-04-13 20:29:31 +02:00
2024-04-13 21:46:15 +02:00
if ( cct ) values [ "cct" ] = cct ;
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 ;
2024-04-13 20:29:31 +02:00
return values ;
}
2024-04-13 21:46:15 +02:00
2024-04-13 20:29:31 +02:00
//
if ( register == 4 )
{
values [ "master_node_version" ] = bytes [ 1 ] + "." + bytes [ 2 ] ;
//logger.debug("FW Version", register, bytes);
}
//Napätie
if ( register == 74 )
{
let voltage = ( bytesToInt ( bytes ) * 0.1 ) . toFixed ( 1 ) ;
values [ "voltage" ] = Number ( voltage ) ;
}
//Prúd
if ( register == 75 )
{
let current = bytesToInt ( bytes ) ;
values [ "current" ] = current ;
}
//výkon
if ( register == 76 )
{
let power = ( bytesToInt ( bytes ) * 0.1 ) . toFixed ( 2 ) ;
values [ "power" ] = Number ( power ) ;
}
//účinník
if ( register == 77 )
{
let power _factor = Math . cos ( bytesToInt ( bytes ) * 0.1 ) . toFixed ( 2 ) ;
values [ "power_factor" ] = Number ( power _factor ) ;
}
//frekvencia
if ( register == 78 )
{
let frequency = ( bytesToInt ( bytes ) * 0.1 ) . toFixed ( 2 ) ;
values [ "frequency" ] = Number ( frequency ) ;
}
//energia
if ( register == 79 )
{
let energy = bytesToInt ( bytes ) ;
//Energiu treba reportovať v kWh. Teda číslo, ktoré príde treba podeliť 1000. Toto som ti možno zle napísal.
values [ "energy" ] = energy / 1000 ;
}
//doba života
if ( register == 80 )
{
let lifetime = ( bytesToInt ( bytes ) / 60 ) . toFixed ( 2 ) ;
values [ "lifetime" ] = Number ( lifetime ) ;
}
//nastavenie profilu
if ( register == 8 )
{
let time _schedule _settings = bytesToInt ( bytes ) ;
values [ "time_schedule_settings" ] = time _schedule _settings ;
}
//skupinová adresa 1
if ( register == 3 )
{
let gr _add _1 = bytesToInt ( byte0 ) ;
values [ "gr_add_1" ] = gr _add _1 ;
let gr _add _2 = bytesToInt ( byte1 ) ;
values [ "gr_add_2" ] = gr _add _2 ;
let gr _add _3 = bytesToInt ( byte2 ) ;
values [ "gr_add_3" ] = gr _add _3 ;
let gr _add _4 = bytesToInt ( byte3 ) ;
values [ "gr_add_4" ] = gr _add _4 ;
}
//naklon
if ( register == 84 )
{
let temp ;
if ( byte3 >= 128 )
{
temp = ( byte3 - 128 ) * ( - 1 ) ;
}
else
{
temp = byte3 ;
}
let inclination _x ;
if ( byte2 >= 128 )
{
inclination _x = ( byte2 - 128 ) * ( - 1 ) ;
}
else
{
inclination _x = byte2 ;
}
let inclination _y ;
if ( byte1 >= 128 )
{
inclination _y = ( byte1 - 128 ) * ( - 1 ) ;
}
else
{
inclination _y = byte1 ;
}
let inclination _z ;
if ( byte0 >= 128 )
{
inclination _z = ( byte0 - 128 ) * ( - 1 ) ;
}
else
{
inclination _z = byte0 ;
}
values [ "temperature" ] = temp ;
//náklon x
values [ "inclination_x" ] = inclination _x ;
//náklon y
values [ "inclination_y" ] = inclination _y ;
//náklon z
values [ "inclination_z" ] = inclination _z ;
}
let h = byte3 ;
let m = byte2 ;
let s = byte1 ;
let timestamp ;
if ( register == 87 || register == 6 || register == 7 )
{
//if(byte3 < 10) h = "0" + byte3;
//if(byte2 < 10) m = "0" + byte2;
//if(byte1 < 10) s = "0" + byte1;
var d = new Date ( ) ;
d . setHours ( h ) ;
d . setMinutes ( m ) ;
d . setSeconds ( s ) ;
timestamp = d . getTime ( ) ;
}
//aktuálny čas
if ( register == 87 )
{
//Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
//values["actual_time"] = h + ":" + m + ":" + s;
values [ "actual_time" ] = timestamp ;
}
//čas súmraku
if ( register == 6 )
{
//Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
//values["dusk_time"] = h + ":" + m + ":" + s;
values [ "dusk_time" ] = timestamp ;
}
//čas úsvitu
if ( register == 7 )
{
//Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
//values["dawn_time"] = h + ":" + m + ":" + s;
values [ "dawn_time" ] = timestamp ;
}
//FW verzia
if ( register == 89 )
{
//formát: "Byte3: Byte2.Byte1 (Byte0)"
values [ "fw_version" ] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")" ;
}
2024-04-13 21:46:15 +02:00
if ( register == 95 )
{
values [ "lux_level" ] = ( byte1 * 256 ) + byte0 ;
}
if ( register == 104 )
{
values [ "movement_timeout" ] = ( byte1 * 256 ) + byte0 ;
values [ "movement_state" ] = byte2 ;
}
2024-04-13 20:29:31 +02:00
return values ;
}
//byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
function com _generic ( adresa , rec , rw , register , name , byte1 , byte2 , byte3 , byte4 ) {
let resp = [ ] ;
let cmd = register ;
if ( typeof adresa === 'string' ) adresa = parseInt ( adresa ) ;
if ( typeof byte1 === 'string' ) byte1 = parseInt ( byte1 ) ;
if ( typeof byte2 === 'string' ) byte2 = parseInt ( byte2 ) ;
if ( typeof byte3 === 'string' ) byte3 = parseInt ( byte3 ) ;
if ( typeof byte4 === 'string' ) byte4 = parseInt ( byte4 ) ;
if ( rw === 0 )
{
cmd = cmd + 0x8000 ;
}
//master
if ( rec === 0 ) adresa = 0 ;
if ( rec === 2 )
{
adresa = 0xffffffff ; //Broadcast
}
//recipient
if ( rec === 3 )
{
resp . push ( 0xFF ) ;
resp . push ( 0xFF ) ;
resp . push ( 0xFF ) ;
resp . push ( 0xFF ) ;
resp . push ( adresa & 0xFF ) ; //band
}
else
{
resp . push ( ( adresa >> 24 ) & 0xFF ) ; //rshift
resp . push ( ( adresa >> 16 ) & 0xFF ) ;
resp . push ( ( adresa >> 8 ) & 0xFF ) ;
resp . push ( adresa & 0xFF ) ;
if ( rec === 2 )
{
resp . push ( 0xFF ) ;
}
else resp . push ( 0 ) ;
}
resp . push ( ( cmd >> 8 ) & 0xFF ) ; //rshift
resp . push ( cmd & 0xFF ) ; //band
resp . push ( byte1 & 0xFF ) ; //band
resp . push ( byte2 & 0xFF ) ; //band
resp . push ( byte3 & 0xFF ) ; //band
resp . push ( byte4 & 0xFF ) ; //band
//let data = '12345';
let crc = crc16 ( 'ARC' , resp ) ;
let c1 = ( crc >> 8 ) & 0xFF ;
let c2 = crc & 0xFF ;
resp . push ( c1 ) ;
resp . push ( c2 ) ;
//logger.debug("checksum", crc);
//logger.debug("resp", resp);
return resp ;
}
2024-04-13 21:46:15 +02:00
// 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
// }
// }
// }
// }
// }