Author Topic: Custom node/metrics  (Read 4319 times)

HeneryH

  • Full Member
  • ***
  • Posts: 229
Custom node/metrics
« on: October 12, 2017, 08:42:31 PM »
I just saw one reference earlier today but can't seem to remember what I searched for and can't find it now...

Can someone please post a help note on how to create a new node type with a new metric type?

I created an RFID Mot that reads the Unique ID off cards and sends to them to the GateWay Mot as a metric type RFID:xxxxxxxx where xxxxxxxx is a hex number.

What the server does when it gets that message remains an open question to be tackled after I first get the gateway to receive and recognize it.

Thanks

sparky

  • Sr. Member
  • ****
  • Posts: 296
  • Country: us

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #2 on: October 12, 2017, 09:39:08 PM »
Was it this post;

https://lowpowerlab.com/forum/projects/rfid-moteino-controled-access-system-(finished)/msg2801/#msg2801
No, it was something from Felix saying that Metrics are of of the form "Metric:Value" and that the Metric has to be added to some config file on the gateway so that it is defined and recognized.

I'm hoping there is another edit to create a new type of node in addition to the new type of metric.

kni

  • NewMember
  • *
  • Posts: 41
  • Country: us
  • The Knight who says Ni
Re: Custom node/metrics
« Reply #3 on: October 13, 2017, 07:46:17 AM »
This is not the thread(droid) you are looking for, but have you read the help text in the source code?
https://github.com/LowPowerLab/RaspberryPi-Gateway/blob/master/metrics.js#L22

Reminds me that creating a new metric is on my to-do list as well.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #4 on: October 13, 2017, 10:09:45 AM »
Awesome, thanks.

The following may seem specific to the application I am working but the concepts remain valid for any new Mot that someone wants to create so I hope you don't mind me proceeding with the discussion...

So for RFID Reader that is sending across the following string showing the Unique ID (UID) of the presented card:
Code: [Select]
RFID UID:5007de16

If I put a metric.js line like
Code: [Select]
RFID_UID: { name:'UID', regexp:/UID\:([0-9a-fA-F]+)/i, value:'', unit:'', },

Then the gateway should register the receipt of the RFID tag.  The data is not numeric in the sense of temperature of similar so not much can be displayed except maybe the log of the event.

Maybe create a Mot type for the RFID Reader with nothing special for settings.
Code: [Select]
  RFIDMote: {
    label  : 'RFID Sensor',
    icon   : 'icon_sonar.png',   <-- create one
    settings: { 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
},

Maybe further investigation of this file will be able to react to the presented ID and reply back to the gate lock with an 'open' command of some type.
« Last Edit: October 13, 2017, 11:12:57 AM by HeneryH »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #5 on: October 13, 2017, 11:15:15 AM »
HeneryH,
Your metric has to be numeric, or else you have to assign a static value to each incoming non-numeric value, to be saved as the actual value.
Look at the GARAGE metics for instance, or the SwitchMote ones. Each incoming word value (OPENING, OPEN etc) has a numeric value assigned to be saved /logged.
THe easiest is to send that value in decimal values which can be extracted directly. I don't think hex will work.
BUT you can use the valuation() function to extract your value and manipulate however you want, and then return a value based on it.
For instance the FH metric:

Code: [Select]
FH : { name:'F', regexp:/\bF\:(-?\d+)\b/i, value:'', duplicateInterval:3600, valuation:function(value) {return value/100;}, unit:'°', pin:1, graph:1, graphValSuffix:'F', graphOptions:{ legendLbl:'Temperature', lines: { lineWidth:1 }}}

Here the node sends the temperature without decimal point, so it needs to be divided by 100 to get the actual value. This is a simple example that illustrates how you would manipulate a value.
For a hex (as defined by your regex), you would get the matched value as a string, then you can use javascript to extract the number you need from it.
I hope this helps.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #6 on: October 13, 2017, 11:21:58 AM »
Thanks for the clarification Felix.  I can just turn it into the numeric equivalent of the hex.  The cards I am using are only eight characters.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #7 on: October 13, 2017, 12:48:24 PM »
Felix,
   Do does the evaluation of the reg expressions go in order and kick out if one hits?  Or maybe alternatively, go through them all and the last one standing wins?

Code: [Select]
exports.metrics = {
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 01'},
  RFID_UID : { name:'UID', regexp:/UID:yyyy/i, value:'Card 02'},
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 03'},
  RFID_UID : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:'Unknown Card'},
};

Or more simply

Code: [Select]
exports.metrics = {
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Known Card'},
  RFID_UID : { name:'UID', regexp:/UID:yyyy/i, value:'Known Card'},
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Known Card'},
  RFID_UID : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:'Unknown Card'},
};

Where xxxx, yyyy and zzzz are the known UIDs and if non of those hit then it will get set to "Unknown"?

Paired with
Code: [Select]
exports.events = {
  RFIDAlert : { label:'RFID : Card Detected', icon:'audio', descr:'Alert sound when RFID Card is detected',
                                         serverExecute:function(node) {
                                                if (node.metrics['UID'] && (
                                                           node.metrics['UID'].value == 'Card 01' ||
                                                           node.metrics['UID'].value == 'Card 02' ||
                                                           node.metrics['UID'].value == 'Card 03' ||
                                                           node.metrics['UID'].value == 'Card 04'
                                                           ) {
                                                      io.sockets.emit('PLAYSOUND', 'sounds/access_granted.wav');
                                                } else {
                                                      io.sockets.emit('PLAYSOUND', 'sounds/access_denied.wav');
                                               };                  <-- what is with this semicolon? 
                                         }
},};
« Last Edit: October 13, 2017, 01:06:33 PM by HeneryH »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #8 on: October 13, 2017, 12:54:40 PM »
Your metrics are not conforming to the expected metric:value format, you only have a value.
First match wins.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #9 on: October 13, 2017, 01:01:47 PM »
How about the correction above? 

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #10 on: October 13, 2017, 01:11:50 PM »
Thats better but you have to also assign a numeric logValue if the value is not numeric.
See these samples, notice the logValue 0 and 1:

Code: [Select]
closed : { name:'Status', regexp:/(?:STS\:)?(CLS|CLOSED)/i, value:'CLOSED', pin:1, graphValPrefix:' Door: ', graph:1, logValue:0 },
open : { name:'Status', regexp:/(?:STS\:)?(OPN|OPEN)\b/i, value:'OPEN', pin:1, graph:1, logValue:2 },

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #11 on: October 13, 2017, 01:18:04 PM »
Awesome, I will be testing this out tonight.

Code: [Select]
exports.metrics = {
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 01', logValue:1},
  RFID_UID : { name:'UID', regexp:/UID:yyyy/i, value:'Card 02', logValue:2},
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 03', logValue:3},
  RFID_UID : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:'Unknown Card', logValue:0},
};

//example of overriding an event
exports.events = {
  RFIDAlert : { label:'RFID : Card Detected', icon:'audio', descr:'Alert sound when RFID Card is detected',
                                         serverExecute:function(node) {
                                                if (node.metrics['UID'] && (
                                                           node.metrics['UID'].value == 'Card 01' ||
                                                           node.metrics['UID'].value == 'Card 02' ||
                                                           node.metrics['UID'].value == 'Card 03' ||
                                                           node.metrics['UID'].value == 'Card 04'
                                                           ) {
                                                      io.sockets.emit('PLAYSOUND', 'sounds/access_granted.wav');
                                                } else {
                                                      io.sockets.emit('PLAYSOUND', 'sounds/access_denied.wav');
                                               };                  <-- what is with this semicolon? 
                                         }
                              },
};

exports.motes = {
  RFIDMote: {
      label  : 'RFID Sensor',
      icon   : 'icon_sonar.png',   <-- create one
      settings: { 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
  },
}
« Last Edit: October 13, 2017, 01:33:36 PM by HeneryH »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #12 on: October 13, 2017, 01:30:50 PM »
You forgot your correction  ;)

Code: [Select]
regexp:/UID:xxxx/i

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #13 on: October 13, 2017, 01:33:12 PM »
You forgot your correction  ;)

Code: [Select]
regexp:/UID:xxxx/i
Too many edit buffers open  :)  Got it.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #14 on: October 14, 2017, 02:08:44 PM »
The following code is not executing as expected.  Can anyone spot the error?

If I set the hardcoded  "  || 1"  to force the expression to be true, then the doorbell sound rings. 

If I set the hardcoded  "  || 0" to have the evaluator check the UID of the card, it does not work.

The gateway is receiving the following message from the RFID Mot
Code: [Select]
[10-14-17_17:58:18.724] [LOG]   >: [22] RFID UID:90a3e116 BAT:0.98v   [RSSI:-49][ACK-sent]
[10-14-17_17:58:18.826] [LOG]   post: /home/pi/gateway/data/db/0022_V.bin[1508003898,0.98]
[10-14-17_17:58:18.852] [LOG]   post: /home/pi/gateway/data/db/0022_RSSI.bin[1508003898,-49]
[10-14-17_17:58:19.008] [LOG]      [22] DB-Updates:1

So the gateway is getting the UID of 90a3e116 as expected.

The metric file should be getting that and mapping the value to "Card 01" then evaluating the event to ring the doorbell when there is a match for Card 01.

Code: [Select]
exports.metrics = {
  RFID_UID : { name:'UID', regexp:/UID:90a3e116/i, value:'Card 01', logValue:1},
  RFID_UID : { name:'UID', regexp:/UID:8008e616/i, value:'Card 02', logValue:2},
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 03', logValue:3},
  RFID_UID : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:"Unknown Card", logValue:0},
};

//example of overriding an event
exports.events = {

  rfidSound : { label:'RFID : Xxx ', icon:'audio', descr:'Play either grant or denysound when RFID card is detected', serverExecute:function(node) { if (node.metrics['UID'] && (node.metrics['UID'].value == 'Card 01' || 0 )) { io.sockets.emit('PLAYSOUND', 'sounds/doorbell.wav'); }; } },

};

So the either the mapping of the value to "Card 01" is not happening or the evaluation of node.metrics['UID'].value == 'Card 01'  is not triggering as TRUE.

I was thinking that maybe the string compare wasn't behaving properly with strings so I tried switching to strcmp(a,b) but that syntax wasn't accepted.  I tried double-quotes instead of single quotes without success.  I'm not 100% on the syntax being used here so if there is any advice I would greatly appreciate it.

« Last Edit: October 14, 2017, 02:10:57 PM by HeneryH »

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #15 on: October 16, 2017, 09:49:02 AM »
Until I find the error in the code posted immediately prior to this post, I will try to use the node.metrics['UID'].logValue rather than the string based node.metrics['UID'].value.  While it won't read as well, if I can get it to at least work, it will be making progress.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #16 on: October 17, 2017, 09:34:15 AM »
The following code is not executing as expected.  Can anyone spot the error?

If I set the hardcoded  "  || 1"  to force the expression to be true, then the doorbell sound rings. 

If I set the hardcoded  "  || 0" to have the evaluator check the UID of the card, it does not work.

The gateway is receiving the following message from the RFID Mot
Code: [Select]
[10-14-17_17:58:18.724] [LOG]   >: [22] RFID UID:90a3e116 BAT:0.98v   [RSSI:-49][ACK-sent]
[10-14-17_17:58:18.826] [LOG]   post: /home/pi/gateway/data/db/0022_V.bin[1508003898,0.98]
[10-14-17_17:58:18.852] [LOG]   post: /home/pi/gateway/data/db/0022_RSSI.bin[1508003898,-49]
[10-14-17_17:58:19.008] [LOG]      [22] DB-Updates:1

So the gateway is getting the UID of 90a3e116 as expected.

The metric file should be getting that and mapping the value to "Card 01" then evaluating the event to ring the doorbell when there is a match for Card 01.

Code: [Select]
exports.metrics = {
  RFID_UID : { name:'UID', regexp:/UID:90a3e116/i, value:'Card 01', logValue:1},
  RFID_UID : { name:'UID', regexp:/UID:8008e616/i, value:'Card 02', logValue:2},
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 03', logValue:3},
  RFID_UID : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:"Unknown Card", logValue:0},
};

//example of overriding an event
exports.events = {

  rfidSound : { label:'RFID : Xxx ', icon:'audio', descr:'Play either grant or denysound when RFID card is detected', serverExecute:function(node) { if (node.metrics['UID'] && (node.metrics['UID'].value == 'Card 01' || 0 )) { io.sockets.emit('PLAYSOUND', 'sounds/doorbell.wav'); }; } },

};

So the either the mapping of the value to "Card 01" is not happening or the evaluation of node.metrics['UID'].value == 'Card 01'  is not triggering as TRUE.

I was thinking that maybe the string compare wasn't behaving properly with strings so I tried switching to strcmp(a,b) but that syntax wasn't accepted.  I tried double-quotes instead of single quotes without success.  I'm not 100% on the syntax being used here so if there is any advice I would greatly appreciate it.

It is definitely the pattern matching that is not working correctly.

Can anyone spot an error in this code?  All card scans return "Unknown Card" as the value.
Code: [Select]
exports.metrics = {
  RFID_UID : { name:'UID', regexp:/UID:90a3e116/i, value:'Card 01', logValue:1},
  RFID_UID : { name:'UID', regexp:/UID:8008e616/i, value:'Card 02', logValue:2},
  RFID_UID : { name:'UID', regexp:/UID:xxxx/i, value:'Card 03', logValue:3},
  RFID_UID : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:"Unknown Card", logValue:0},
};

Here is the output of the server log
Code: [Select]
[10-14-17_17:58:18.724] [LOG]   >: [22] RFID UID:90a3e116 BAT:0.98v   [RSSI:-49][ACK-sent]
[10-14-17_17:58:18.826] [LOG]   post: /home/pi/gateway/data/db/0022_V.bin[1508003898,0.98]
[10-14-17_17:58:18.852] [LOG]   post: /home/pi/gateway/data/db/0022_RSSI.bin[1508003898,-49]
[10-14-17_17:58:19.008] [LOG]      [22] DB-Updates:1

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #17 on: October 17, 2017, 10:14:36 AM »
The patterns work. You can see it work here.
The problem is you are overriding them. Look at the others in metrics.js where they are the same metric, you will notice the variable names are different, otherwise only the last one would stand.
Use a different variable name each time you declare a new variant.

Code: [Select]
exports.metrics = {
  RFID_UID1 : { name:'UID', regexp:/UID:90a3e116/i, value:'Card 01', logValue:1},
  RFID_UID2 : { name:'UID', regexp:/UID:8008e616/i, value:'Card 02', logValue:2},
  RFID_UID3 : { name:'UID', regexp:/UID:xxxx/i, value:'Card 03', logValue:3},
  RFID_UID4 : { name:'UID', regexp:/UID:[0-9a-fA-F]+/i, value:"Unknown Card", logValue:0},
};

Makes sense?

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #18 on: October 17, 2017, 10:25:42 AM »
Sorry, I may be trying something that just wasn't meant to be.

I want one variable that gets set according to the text string received, then test that string in the event rule. 

Sounds like that might not be possible.


Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #19 on: October 17, 2017, 11:24:49 AM »
Just use my adjusted version of your metrics.

HeneryH

  • Full Member
  • ***
  • Posts: 229
Re: Custom node/metrics
« Reply #20 on: October 19, 2017, 09:18:52 AM »
Can someone tell me the syntax of the serverExecute() function and in particular the semi-colon placement?  I'm used to c++ and when I try to put an 'else' clause in my function it doesn't work.  I think the semicolon matters here even though it doesn't in c++.

Thanks

Code: [Select]
                                         serverExecute:function(node) { 
                                                if (node.metrics['UID'] && (
                                                           node.metrics['UID'].value == 'Card 01' ||
                                                           node.metrics['UID'].value == 'Card 02' ||
                                                           node.metrics['UID'].value == 'Card 03' ||
                                                           node.metrics['UID'].value == 'Card 04'
                                                           ) {
                                                      io.sockets.emit('PLAYSOUND', 'sounds/access_granted.wav');
                                                } else {
                                                      io.sockets.emit('PLAYSOUND', 'sounds/access_denied.wav');
                                               };                  <-- what is syntax requirements for thiss emicolon? 
                                         }

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Custom node/metrics
« Reply #21 on: October 19, 2017, 01:08:59 PM »
Javascript != c++  :D

You can omit that semicolon, and in fact you can omit the other in the main if as well.