@@ -31,6 +31,7 @@ var nconf = require('nconf'); //https://github
3131var JSON5 = require ( 'json5' ) ; //https://github.com/aseemk/json5
3232var path = require ( 'path' ) ;
3333var dbDir = 'data/db' ;
34+ var packageJson = require ( './package.json' )
3435var metricsFile = 'metrics.js' ;
3536var userMetricsDir = 'userMetrics' ;
3637nconf . argv ( ) . file ( { file : path . resolve ( __dirname , 'settings.json5' ) , format : JSON5 } ) ;
@@ -107,14 +108,13 @@ var transporter = nodemailer.createTransport({
107108 }
108109} ) ;
109110
110- //global.LOG = function(data) { process.stdout.write(data || ''); }
111- //global.LOGln = function(data) { process.stdout.write((data || '') + '\n'); }
112- global . sendEmail = function ( SUBJECT , BODY ) {
111+ global . sendEmail = function ( SUBJECT , BODY , ATTACHMENTS ) {
113112 var mailOptions = {
114113 from :
'Moteino Gateway <[email protected] >' , 115114 to : settings . credentials . emailAlertsTo . value , // list of receivers, comma separated
116115 subject : SUBJECT ,
117- text : BODY
116+ text : BODY ,
117+ attachments : ATTACHMENTS
118118 //html: '<b>Hello world ?</b>' // html body
119119 } ;
120120 transporter . sendMail ( mailOptions , function ( error , info ) {
@@ -158,8 +158,8 @@ global.handleNodeEvents = function(node) {
158158 {
159159 for ( var key in node . events )
160160 {
161- var enabled = node . events [ key ] ;
162- if ( enabled )
161+ try {
162+ if ( node . events [ key ] && node . events [ key ] . enabled )
163163 {
164164 var evt = metricsDef . events [ key ] ;
165165 if ( evt . serverExecute != undefined )
@@ -168,15 +168,9 @@ global.handleNodeEvents = function(node) {
168168 }
169169 catch ( ex ) { console . warn ( 'Event ' + key + ' execution failed: ' + ex . message ) ; }
170170 }
171+ } catch ( ex ) { console . warn ( '-------> EXCEPTION: nodeId:' + node . _id + ' key:' + key + ' JSON: ' + JSON . stringify ( node ) ) ; throw ex ; }
171172 }
172173 }
173- // if (metricsDef.motes[node.type] && metricsDef.motes[node.type].events)
174- // for (var eKey in metricsDef.motes[node.type].events)
175- // {
176- // var nodeEvent = metricsDef.motes[node.type].events[eKey];
177- // if (nodeEvent.serverExecute != undefined)
178- // nodeEvent.serverExecute(node);
179- // }
180174}
181175
182176//authorize handshake - make sure the request is proxied from localhost, not from the outside world
@@ -207,7 +201,7 @@ io.sockets.on('connection', function (socket) {
207201 socket . emit ( 'EVENTSDEF' , metricsDef . events ) ;
208202 socket . emit ( 'SETTINGSDEF' , settings ) ;
209203 socket . emit ( 'SERVERTIME' , Date . now ( ) ) ;
210- socket . emit ( 'SERVERSTARTTIME ' , Date . now ( ) - process . uptime ( ) * 1000 ) ;
204+ socket . emit ( 'SERVERINFO ' , { uptime : ( Date . now ( ) - process . uptime ( ) * 1000 ) , version : packageJson . version } ) ;
211205
212206 //pull all nodes from the database and send them to client
213207 db . find ( { _id : { $exists : true } } , function ( err , entries ) {
@@ -233,10 +227,10 @@ io.sockets.on('connection', function (socket) {
233227 dbNode . type = node . type || undefined ;
234228 dbNode . label = node . label || undefined ;
235229 dbNode . descr = node . descr || undefined ;
230+ dbNode . settings = node . settings || undefined ;
236231 dbNode . hidden = ( node . hidden == 1 ? 1 : undefined ) ;
237232 db . update ( { _id : dbNode . _id } , { $set : dbNode } , { } , function ( err , numReplaced ) { /*console.log('UPDATENODESETTINGS records replaced:' + numReplaced);*/ } ) ;
238233 io . sockets . emit ( 'UPDATENODE' , dbNode ) ; //post it back to all clients to confirm UI changes
239- //console.log("UPDATE NODE SETTINGS found docs:" + entries.length);
240234 }
241235 } ) ;
242236 } ) ;
@@ -256,7 +250,6 @@ io.sockets.on('connection', function (socket) {
256250 } ) ;
257251
258252 socket . on ( 'EDITNODEEVENT' , function ( nodeId , eventKey , enabled , remove ) {
259- //console.log('**** EDITNODEEVENT **** key:' + eventKey + ' enabled:' + enabled + ' remove:' + remove);
260253 db . find ( { _id : nodeId } , function ( err , entries ) {
261254 if ( entries . length == 1 )
262255 {
@@ -267,22 +260,39 @@ io.sockets.on('connection', function (socket) {
267260 if ( eventKey == key )
268261 {
269262 if ( ! dbNode . events ) dbNode . events = { } ;
270- dbNode . events [ eventKey ] = ( remove ? undefined : ( enabled ? 1 : 0 ) ) ;
271- db . update ( { _id : dbNode . _id } , { $set : dbNode } , { } , function ( err , numReplaced ) { /*console.log('UPDATEMETRICSETTINGS records replaced:' + numReplaced);*/ } ) ;
263+ if ( ! remove )
264+ dbNode . events [ eventKey ] = { enabled : ( enabled ? 1 : 0 ) } ;
265+ else
266+ dbNode . events [ eventKey ] = undefined ;
272267
273- if ( metricsDef . events [ eventKey ] && metricsDef . events [ eventKey ] . scheduledExecute )
268+ scheduled = false ;
269+ if ( ! remove && metricsDef . events [ eventKey ] && metricsDef . events [ eventKey ] . scheduledExecute )
270+ {
274271 if ( enabled && ! remove )
272+ {
275273 schedule ( dbNode , eventKey ) ;
274+ scheduled = true ;
275+ }
276276 else //either disabled or removed
277+ {
277278 for ( var s in scheduledEvents )
279+ {
278280 if ( scheduledEvents [ s ] . nodeId == nodeId && scheduledEvents [ s ] . eventKey == eventKey )
279281 {
280282 console . log ( '**** REMOVING SCHEDULED EVENT - nodeId:' + nodeId + ' event:' + eventKey ) ;
281283 clearTimeout ( scheduledEvents [ s ] . timer ) ;
282284 scheduledEvents . splice ( scheduledEvents . indexOf ( scheduledEvents [ s ] ) , 1 )
285+ dbNode . events [ eventKey ] . executeDateTime = undefined ;
283286 }
287+ }
288+ }
289+ }
284290
285- io . sockets . emit ( 'UPDATENODE' , dbNode ) ; //post it back to all clients to confirm UI changes
291+ if ( ! scheduled )
292+ {
293+ db . update ( { _id : dbNode . _id } , { $set : dbNode } , { } , function ( err , numReplaced ) { /*console.log('UPDATEMETRICSETTINGS records replaced:' + numReplaced);*/ } ) ;
294+ io . sockets . emit ( 'UPDATENODE' , dbNode ) ; //post it back to all clients to confirm UI changes
295+ }
286296 return ;
287297 }
288298 }
@@ -291,7 +301,6 @@ io.sockets.on('connection', function (socket) {
291301
292302 socket . on ( 'DELETENODE' , function ( nodeId ) {
293303 //delete all node-metric log files
294- console . log ( "DELETENODE settings.general.keepMetricLogsOnDelete.value: " + settings . general . keepMetricLogsOnDelete . value ) ;
295304 if ( settings . general . keepMetricLogsOnDelete . value != 'true' )
296305 db . find ( { _id : nodeId } , function ( err , entries ) {
297306 if ( entries . length == 1 )
@@ -485,50 +494,35 @@ function sortNodes(entries) {
485494
486495global . msgHistory = new Array ( ) ;
487496global . processSerialData = function ( data ) {
488- var regexMaster = / \[ ( \d + ) \] ( [ ^ \[ \] \ n] + ) (?: \[ (?: R S S I | S S ) \: - ? ( \d + ) \] ) ? . * / gi; //modifiers: g:global i:caseinsensitive
497+ var regexMaster = / \[ ( \d + ) \] ( [ ^ \n ] + ) / gi; //modifiers: g:global i:caseinsensitive
489498 var match = regexMaster . exec ( data ) ;
490499 console . log ( '>: ' + data )
491500
492501 if ( match != null )
493502 {
494503 var msgTokens = match [ 2 ] ;
495504 var id = parseInt ( match [ 1 ] ) ; //get ID of node
496- var rssi = match [ 3 ] != undefined ? parseInt ( match [ 3 ] ) : undefined ; //get rssi (signal strength)
497505
498506 db . find ( { _id : id } , function ( err , entries ) {
499- var existingNode = new Object ( ) ;
507+ var existingNode = { } ;
500508 var hasMatchedMetrics = false ;
501- if ( entries . length == 1 )
502- { //update
503- existingNode = entries [ 0 ] ;
504- }
509+ if ( entries . length == 1 ) existingNode = entries [ 0 ] ; //update
505510
506511 //check for duplicate messages - this can happen when the remote node sends an ACK-ed message but does not get the ACK so it resends same message repeatedly until it receives an ACK
507512 if ( existingNode . updated != undefined && ( Date . now ( ) - existingNode . updated < 500 ) && msgHistory [ id ] == msgTokens )
508- { console . log ( " DUPLICATE, skipping..." ) ; return ; }
513+ {
514+ console . log ( " DUPLICATE, skipping..." ) ;
515+ return ;
516+ }
509517
510518 msgHistory [ id ] = msgTokens ;
511-
512- //console.log('FOUND ENTRY TO UPDATE: ' + JSON.stringify(existingNode));
513519 existingNode . _id = id ;
514- existingNode . rssi = rssi ; //update signal strength we last heard from this node, regardless of any matches
515520 existingNode . updated = Date . now ( ) ; //update timestamp we last heard from this node, regardless of any matches
516- if ( existingNode . metrics == undefined )
517- existingNode . metrics = new Object ( ) ;
518- if ( existingNode . events == undefined )
519- existingNode . events = new Object ( ) ;
521+ if ( existingNode . metrics == undefined ) existingNode . metrics = { } ;
520522
521523 var regexpTokens = / [ \w \: \. \$ \! \\ \' \" \? \[ \] \- \( \) @ % ^ & # + \/ < > * ~ = , | ] + / ig; //match (almost) any non space human readable character
522524 while ( match = regexpTokens . exec ( msgTokens ) ) //extract each token/value pair from the message and process it
523525 {
524- // //V/VBAT/VOLTS is special, applies to whole node so save it as a node level metric instead of in the node metric collection
525- // if (metricsDef.metrics.V.regexp.test(match[0]))
526- // {
527- // var tokenMatch = metricsDef.metrics.V.regexp.exec(match[0]);
528- // existingNode.V = tokenMatch[1] || tokenMatch[0]; //extract the voltage part
529- // continue;
530- // }
531-
532526 var matchingMetric ;
533527 //try to match a metric definition
534528 for ( var metric in metricsDef . metrics )
@@ -539,7 +533,7 @@ global.processSerialData = function (data) {
539533 //console.log('TOKEN MATCHED: ' + metricsDef.metrics[metric].regexp);
540534 var tokenMatch = metricsDef . metrics [ metric ] . regexp . exec ( match [ 0 ] ) ;
541535 matchingMetric = metricsDef . metrics [ metric ] ;
542- if ( existingNode . metrics [ matchingMetric . name ] == null ) existingNode . metrics [ matchingMetric . name ] = new Object ( ) ;
536+ if ( existingNode . metrics [ matchingMetric . name ] == null ) existingNode . metrics [ matchingMetric . name ] = { } ;
543537 existingNode . metrics [ matchingMetric . name ] . label = existingNode . metrics [ matchingMetric . name ] . label || matchingMetric . name ;
544538 existingNode . metrics [ matchingMetric . name ] . descr = existingNode . metrics [ matchingMetric . name ] . descr || matchingMetric . descr || undefined ;
545539 existingNode . metrics [ matchingMetric . name ] . value = metricsDef . determineValue ( matchingMetric , tokenMatch ) ;
@@ -565,15 +559,15 @@ global.processSerialData = function (data) {
565559 }
566560
567561 //console.log('TOKEN MATCHED OBJ:' + JSON.stringify(existingNode));
568- hasMatchedMetrics = true ;
562+ if ( matchingMetric . name != 'RSSI' ) hasMatchedMetrics = true ; //excluding RSSI because noise can produce a packet with a valid RSSI reading
569563 break ; //--> this stops matching as soon as 1 metric definition regex is matched on the data. You could keep trying to match more definitions and that would create multiple metrics from the same data token, but generally this is not desired behavior.
570564 }
571565 }
566+ //if (!matchingMetric) console.log('TOKEN NONMATCHED: ' + match[0]);
572567 }
573568
574569 //prepare entry to save to DB, undefined values will not be saved, hence saving space
575- var entry = { _id :id , updated :existingNode . updated , type :existingNode . type || undefined , label :existingNode . label || undefined , descr :existingNode . descr || undefined , hidden :existingNode . hidden || undefined , rssi :existingNode . rssi , metrics :Object . keys ( existingNode . metrics ) . length > 0 ? existingNode . metrics : { } , events : Object . keys ( existingNode . events ) . length > 0 ? existingNode . events : undefined } ;
576- //console.log('UPDATING ENTRY: ' + JSON.stringify(entry));
570+ var entry = { _id :id , updated :existingNode . updated , type :existingNode . type || undefined , label :existingNode . label || undefined , descr :existingNode . descr || undefined , hidden :existingNode . hidden || undefined , rssi :existingNode . rssi , metrics :Object . keys ( existingNode . metrics ) . length > 0 ? existingNode . metrics : { } , events : existingNode . events , settings : existingNode . settings } ;
577571
578572 //save to DB
579573 db . findOne ( { _id :id } , function ( err , doc ) {
@@ -584,10 +578,7 @@ global.processSerialData = function (data) {
584578 db . insert ( entry ) ;
585579 console . log ( ' [' + id + '] DB-Insert new _id:' + id ) ;
586580 }
587- else
588- {
589- return ;
590- }
581+ else return ;
591582 }
592583 else
593584 db . update ( { _id : id } , { $set : entry } , { } , function ( err , numReplaced ) { console . log ( ' [' + id + '] DB-Updates:' + numReplaced ) ; } ) ;
@@ -638,12 +629,22 @@ function schedule(node, eventKey) {
638629
639630 //remember the timer ID so we can clear it later
640631 scheduledEvents . push ( { nodeId :node . _id , eventKey :eventKey , timer :theTimer } ) ; //save nodeId, eventKey and timer (needs to be removed if the event is disabled/removed from the UI)
632+ node . events [ eventKey ] . executeDateTime = new Date ( Date . now ( ) + nextRunTimeout ) ; //actual datetime when this is scheduled to execute
633+
634+ //save to DB
635+ db . findOne ( { _id :node . _id } , function ( err , dbNode ) {
636+ dbNode . events = node . events ;
637+ db . update ( { _id :dbNode . _id } , { $set : dbNode } , { } , function ( err , numReplaced ) { console . log ( ' [' + dbNode . _id + '] DB-Updates:' + numReplaced ) ; } ) ;
638+ //publish updated node to clients
639+ io . sockets . emit ( 'UPDATENODE' , dbNode ) ;
640+ } ) ;
641641}
642642
643643//run a scheduled event and reschedule it
644644function runAndReschedule ( functionToExecute , node , eventKey ) {
645645 console . log ( '**** RUNNING SCHEDULED EVENT - nodeId:' + node . _id + ' event:' + eventKey + '...' ) ;
646- try {
646+ try
647+ {
647648 functionToExecute ( node , eventKey ) ;
648649 }
649650 catch ( ex )
@@ -662,15 +663,13 @@ db.find({ events : { $exists: true } }, function (err, entries) {
662663 for ( var k in entries )
663664 for ( var i in entries [ k ] . events )
664665 {
665- if ( entries [ k ] . events [ i ] == 1 ) //enabled events only
666+ if ( entries [ k ] . events [ i ] . enabled ) //enabled events only
666667 {
667- //console.log('Event for ' + JSON.stringify(entries[k].events) + ' : ' + metricsDef.events[i]);
668668 if ( metricsDef . events [ i ] && metricsDef . events [ i ] . nextSchedule && metricsDef . events [ i ] . scheduledExecute )
669669 {
670670 schedule ( entries [ k ] , i ) ;
671671 count ++ ;
672672 }
673673 }
674674 }
675- //console.log('*** Events Register db count: ' + count);
676675} ) ;
0 commit comments