Skip to content

Commit f1bd435

Browse files
committed
8.10 main commit
#manual actions required: - update your settings in new settings.json5 - run npm install - rename any nodes/descriptions to include extra {} around text not wanted in SMS messages
1 parent b04446e commit f1bd435

File tree

9 files changed

+415
-162
lines changed

9 files changed

+415
-162
lines changed

gateway.js

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var nconf = require('nconf'); //https://github
3131
var JSON5 = require('json5'); //https://github.com/aseemk/json5
3232
var path = require('path');
3333
var dbDir = 'data/db';
34+
var packageJson = require('./package.json')
3435
var metricsFile = 'metrics.js';
3536
var userMetricsDir = 'userMetrics';
3637
nconf.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

486495
global.msgHistory = new Array();
487496
global.processSerialData = function (data) {
488-
var regexMaster = /\[(\d+)\]([^\[\]\n]+)(?:\[(?:RSSI|SS)\:-?(\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
644644
function 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

Comments
 (0)