Author Topic: Dynamic. node-specific event trigger [+solution]  (Read 1517 times)

frix

  • NewMember
  • *
  • Posts: 22
Dynamic. node-specific event trigger [+solution]
« on: October 15, 2017, 11:31:53 PM »
Hey guys,

I want to set up an SMS event when the temp goes down a specific threshold, not a big deal. And I can do it no prob. But the only way I have been able to do it is by hard-coding a custom event. All OK. The problem comes when I have a whole network of motes each in a different location and I want to set up the alerts for different temperatures. This would mean I need to define a new custom event for every single temperature threshold I want.

So, playing with things, I found that I can add any specific "setting" to my custom mote. Currently I have this:

Code: [Select]
    settings: {
      lowTempValue: '',
      highTempValue: '',
      lowVoltageValue: ''}, //blank will make it inherit from global settings.json lowVoltageValue, a specific value overrides the general setting, user can always choose his own setting in the UI
  },

And I added the settings:
Code: [Select]
      lowTempValue: {
        value: 20,
        type: 'range',
        min:15,
        max:25,
        description: "a warning icon is shown over the node Icon when the node's voltage is less than this value (typically around 3.5v for a standard Moteino)"
      },
      highTempValue: {
        value: 28,
        type: 'range',
        min:25,
        max:32,
        description: "a warning icon is shown over the node Icon when the node's voltage is less than this value (typically around 3.5v for a standard Moteino)"
      },

Which works great. I now have the three sliders on each of my custom motes:


Now, the question is: Is there a way in which I can program my SMS event to pull the threshold from the individual setting of the mote, instead of the hard-coded value in the event?

Reading through the gateway.js, I see that at the very beginning it's pulling some values from the settings file, I think I want to do the same, but from each specific mote. Any ideas? (see the settings.serial.baud.value call)

Code: [Select]
nconf.argv().file({ file: path.resolve(__dirname, 'settings.json5'), format: JSON5 });
settings = nconf.get('settings');
serial = new serialport.SerialPort(settings.serial.port.value, { baudrate : settings.serial.baud.value, parser: serialport.parsers.readline("\n") }, false);

Thanks!
Frix
« Last Edit: October 16, 2017, 01:22:06 AM by frix »

frix

  • NewMember
  • *
  • Posts: 22
Re: Dynamic. node-specific event trigger
« Reply #1 on: October 16, 2017, 01:21:38 AM »
So, it works!

Super simple, just replace the hard-coded value statement in your event for the value of the node setting. Meaning, change this:
Code: [Select]
      if (node.metrics['C'] && node.metrics['C'].value > 30 && (Date.now() - node.metrics['C'].updated < 2000))
To this:
Code: [Select]
      if (node.metrics['C'] && node.metrics['C'].value > node.settings['highTempValue'] && (Date.now() - node.metrics['C'].updated < 2000))

And voila! dynamic, node-specific events. I can confirm with a bunch of text messages that it's working just fine.

Here's a snippet from my custom_metrics.js file with all the function for your reference:
Code: [Select]
exports.events ={
  tempTooHotSMSLimiter : { label:'TooHotAlert : SMS', icon:'comment', descr:'Send SMS when Temp is > than the setting max, once per hour',
    serverExecute:function(node) {
      if (node.metrics['C'] && node.metrics['C'].value > node.settings['highTempValue'] && (Date.now() - node.metrics['C'].updated < 2000)) /*check if M metric exists and value is MOTION, received less than 2s ago*/
      {
        var approveSMS = false;
        if (node.metrics['C'].lastSMS) /*check if lastSMS value is not NULL ... */
        {
          if (Date.now() - node.metrics['C'].lastSMS > 1800000) /*check if lastSMS timestamp is more than 1hr ago*/
          {
            approveSMS = true;
          }
        }
        else
        {
          approveSMS = true;
        }
        if (approveSMS)
        {
          node.metrics['C'].lastSMS = Date.now();
          sendSMS('Too hot!', 'Temperature alert on: [' + node._id + '] :' + node.label.replace(/\{.+\}/ig, '') + ' @ ' + new Date().toLocaleTimeString());
          db.update({ _id: node._id }, { $set : node}, {}, function (err, numReplaced) { console.log('   ['+node._id+'] DB-Updates:' + numReplaced);}); /*save lastSMS timestamp to DB*/
        }
        else console.log('   ['+node._id+'] TooHotAlert SMS skipped.');
      };
    }
  },

  tempTooColdSMSLimiter : { label:'TooColdAlert : SMS', icon:'comment', descr:'Send SMS when Temp is < than the setting min, once per hour',
    serverExecute:function(node) {
      if (node.metrics['C'] && node.metrics['C'].value < node.settings['lowTempValue'] && (Date.now() - node.metrics['C'].updated < 2000)) /*check if M metric exists and value is MOTION, received less than 2s ago*/
      {
        var approveSMS = false;
        if (node.metrics['C'].lastSMS) /*check if lastSMS value is not NULL ... */
        {
          if (Date.now() - node.metrics['C'].lastSMS > 1800000) /*check if lastSMS timestamp is more than 1hr ago */
          {
            approveSMS = true;
          }
        }
        else
        {
          approveSMS = true;
        }
        if (approveSMS)
        {
          node.metrics['C'].lastSMS = Date.now();
          sendSMS('Too cold!', 'Temperature alert on: [' + node._id + '] :' + node.label.replace(/\{.+\}/ig, '') + ' @ ' + new Date().toLocaleTimeString());
          db.update({ _id: node._id }, { $set : node}, {}, function (err, numReplaced) { console.log('   ['+node._id+'] DB-Updates:' + numReplaced);}); /*save lastSMS timestamp to DB*/
        }
        else console.log('   ['+node._id+'] TooColdAlert SMS skipped.');
      };
    }
  },
};

exports.motes = {
MyMote: {
    label  : 'Temp Node',
    icon   : 'icon_temperature2.png',
    settings: {
      lowTempValue: '',
      highTempValue: '',
      lowVoltageValue: ''}, //blank will make it inherit from global settings.json lowVoltageValue, a specific value overrides the general setting, user can always choose his own setting in the UI
  },
};


Enjoy!
Frix
« Last Edit: October 16, 2017, 01:30:43 AM by frix »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Dynamic. node-specific event trigger [+solution]
« Reply #2 on: October 16, 2017, 11:02:07 PM »
Nice contributions, thanks for sharing the awesome :)