-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: adds support for alert PGNs 126983 and 126985 (#173)
NMEA has standardized PGNs to handle alerts. The main alert is handled in 126983 with the alert text handled in 126985. The alert is sent ~1/sec with the alert text sent ~1/10 sec or possibly longer. Because the notifications schema only allows for a single value, we wait until we have data from both PGNs before we process the update and create the notification.
- Loading branch information
1 parent
6793b21
commit 49f9896
Showing
5 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// ALERT | ||
const debug = require('debug')('n2k-signalk-126983') | ||
|
||
const alertTypes = [{ | ||
"nmea": "Emergency Alarm", | ||
"sk": "emergency" | ||
}, | ||
{ | ||
"nmea": "Alarm", | ||
"sk": "alarm" | ||
}, | ||
{ | ||
"nmea": "Warning", | ||
"sk": "warn" | ||
}, | ||
{ | ||
"nmea": "Caution", | ||
"sk": "alert" | ||
} | ||
] | ||
|
||
module.exports = [{ | ||
node: function(n2k, state) { | ||
var alertType = n2k.fields['Alert Type'].replace(/ /g, '').toLowerCase() | ||
|
||
var alertCategory = n2k.fields['Alert Category'].toLowerCase() | ||
|
||
var path = 'notifications.nmea.' + alertType + '.' + alertCategory + '.' + n2k.fields['Alert System'] + '.' + n2k.fields['Alert ID'] | ||
debug('126983 path: ' + path) | ||
|
||
return path | ||
}, | ||
value: function(n2k, state) { | ||
debug('126983 value') | ||
|
||
var skstate = alertTypes.filter(alertType => alertType.nmea === n2k.fields['Alert Type']) | ||
debug('126983 skstate: ' + skstate[0].sk) | ||
|
||
var alertId = n2k.fields['Alert ID'] | ||
|
||
var value = { | ||
"state": skstate[0].sk, | ||
"method": [ | ||
"visual", | ||
"sound" | ||
], | ||
"message": state.alerts[alertId].textDescription, | ||
"alertType": n2k.fields['Alert Type'], | ||
"alertCategory": n2k.fields['Alert Category'], | ||
"alertSystem": n2k.fields['Alert System'], | ||
"alertId": n2k.fields['Alert ID'], | ||
"dataSourceNetworkIDNAME": n2k.fields['Data Source Network ID NAME'], | ||
"dataSourceInstance": n2k.fields['Data Source Instance'], | ||
"dataSourceIndex-Source": n2k.fields['Data Source Index-Source'], | ||
"occurrence": n2k.fields['Alert Occurrence Number'], | ||
"temporarySilenceStatus": n2k.fields['Temporary Silence Status'], | ||
"acknowledgeStatus": n2k.fields['Acknowledge Status'], | ||
"escalationStatus": n2k.fields['Escalation Status'], | ||
"temporarySilenceSupport": n2k.fields['Temporary Silence Support'], | ||
"acknowledgeSupport": n2k.fields['Acknowledge Support'], | ||
"escalationSupport": n2k.fields['Escalation Support'], | ||
"acknowledgeSourceNetworkIDNAME": n2k.fields['Acknowledge Source Network ID NAME'], | ||
"triggerCondition": n2k.fields['Trigger Condition'], | ||
"thresholdStatus": n2k.fields['Threshold Status'], | ||
"alertPriority": n2k.fields['Alert Priority'], | ||
"alertState": n2k.fields['Alert State'] | ||
} | ||
|
||
//if the alert is silenced or acknowledged then dont alert in SK | ||
if (n2k.fields['Temporary Silence Status'] == 'Temporary Silence' || | ||
n2k.fields['Acknowledge Status'] == 'Acknowledged') { | ||
value.method = [] | ||
} | ||
debug('126983 value: ' + JSON.stringify(value)) | ||
|
||
return value | ||
}, | ||
filter: function(n2k, state) { | ||
return ( | ||
n2k.fields['Alert Type'] && | ||
typeof state === 'object' && | ||
state.alerts && | ||
state.alerts[n2k.fields['Alert ID']] | ||
) | ||
} | ||
}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
//ALERT TEXT | ||
const debug = require('debug')('n2k-signalk-126985') | ||
|
||
module.exports = [{ | ||
filter: function(n2k, state) { | ||
if (typeof state !== 'undefined') { | ||
var alertId = n2k.fields['Alert ID'] | ||
var text = { | ||
languageId: n2k.fields['Language ID'], | ||
textDescription: n2k.fields['Alert Text Description'], | ||
locationTextDescription: n2k.fields['Alert Location Text Description'] || '' | ||
} | ||
//store the alert text in state for use with PGN 126983 | ||
if (!state.alerts) { | ||
state.alerts = {} | ||
} | ||
state.alerts[alertId] = text | ||
|
||
debug('set alert state text: ' + JSON.stringify(text)) | ||
} | ||
return false | ||
}, | ||
source: 'Alert Text' | ||
}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
var chai = require('chai') | ||
chai.Should() | ||
chai.use(require('chai-things')) | ||
chai.use(require('@signalk/signalk-schema').chaiModule) | ||
var expect = chai.expect; | ||
|
||
var mapper = require('./testMapper') | ||
|
||
//provided by PGN 126985 Alert Text | ||
var state = { | ||
"40": { | ||
"alerts": { | ||
"23480": { | ||
"languageId": "English (US)", | ||
"locationTextDescription": "", | ||
"textDescription": "TEST: Temperature over 0" | ||
} | ||
} | ||
} | ||
} | ||
|
||
var value = { | ||
"state": "warn", | ||
"method": [ | ||
"visual", | ||
"sound" | ||
], | ||
"message": "TEST: Temperature over 0", | ||
"alertType": "Warning", | ||
"alertCategory": "Navigational", | ||
"alertSystem": 20, | ||
"alertId": 23480, | ||
"dataSourceNetworkIDNAME": 6458553273545042000, | ||
"dataSourceInstance": 0, | ||
"dataSourceIndex-Source": 0, | ||
"occurrence": 1, | ||
"temporarySilenceStatus": "Not Temporary Silence", | ||
"acknowledgeStatus": "Not Acknowledged", | ||
"escalationStatus": "Not Escalated", | ||
"temporarySilenceSupport": "Supported", | ||
"acknowledgeSupport": "Supported", | ||
"escalationSupport": "Not Supported", | ||
"acknowledgeSourceNetworkIDNAME": 1233993542451364400, | ||
"triggerCondition": "Auto", | ||
"thresholdStatus": "Threshold Exceeded", | ||
"alertPriority": 187, | ||
"alertState": "Active" | ||
} | ||
|
||
describe('126983 Alert', function() { | ||
it('alert without silence or ackknowledgement', function() { | ||
var msg = JSON.parse( | ||
'{"canId":166725416,"prio":2,"src":40,"dst":255,"pgn":126983,"direction":"R","time":"15:48:36.090","fields":{"Alert Type":"Warning","Alert Category":"Navigational","Alert System":20,"Alert ID":23480,"Data Source Network ID NAME":6458553273545042000,"Data Source Instance":0,"Data Source Index-Source":0,"Alert Occurrence Number":1,"Temporary Silence Status":"Not Temporary Silence","Acknowledge Status":"Not Acknowledged","Escalation Status":"Not Escalated","Temporary Silence Support":"Supported","Acknowledge Support":"Supported","Escalation Support":"Not Supported","Acknowledge Source Network ID NAME":1233993542451364400,"Trigger Condition":"Auto","Threshold Status":"Threshold Exceeded","Alert Priority":187,"Alert State":"Active"},"description":"Alert","timestamp":"2020-03-03T15:48:36.494Z"}' | ||
) | ||
var tree = mapper.toNested(msg, state) | ||
tree.should.have.nested.property('notifications.nmea.warning.navigational.20.23480.value') | ||
|
||
expect(tree.notifications.nmea.warning.navigational[20][23480].value).to.deep.include(value) | ||
|
||
var delta = mapper.toDelta(msg) | ||
delta.updates.length.should.equal(1) | ||
}) | ||
|
||
it('alert with temporary silence', function() { | ||
//method should be empty for this test | ||
value.method = [] | ||
value.temporarySilenceStatus = 'Temporary Silence' | ||
|
||
var msg = JSON.parse( | ||
'{"canId":166725416,"prio":2,"src":40,"dst":255,"pgn":126983,"direction":"R","time":"15:48:36.090","fields":{"Alert Type":"Warning","Alert Category":"Navigational","Alert System":20,"Alert ID":23480,"Data Source Network ID NAME":6458553273545042000,"Data Source Instance":0,"Data Source Index-Source":0,"Alert Occurrence Number":1,"Temporary Silence Status":"Temporary Silence","Acknowledge Status":"Not Acknowledged","Escalation Status":"Not Escalated","Temporary Silence Support":"Supported","Acknowledge Support":"Supported","Escalation Support":"Not Supported","Acknowledge Source Network ID NAME":1233993542451364400,"Trigger Condition":"Auto","Threshold Status":"Threshold Exceeded","Alert Priority":187,"Alert State":"Active"},"description":"Alert","timestamp":"2020-03-03T15:48:36.494Z"}' | ||
) | ||
var tree = mapper.toNested(msg, state) | ||
tree.should.have.nested.property('notifications.nmea.warning.navigational.20.23480.value') | ||
|
||
expect(tree.notifications.nmea.warning.navigational[20][23480].value).to.deep.include(value) | ||
|
||
var delta = mapper.toDelta(msg) | ||
delta.updates.length.should.equal(1) | ||
}) | ||
|
||
it('alert with acknowledgement', function() { | ||
value.temporarySilenceStatus = 'Not Temporary Silence' | ||
value.acknowledgeStatus = 'Acknowledged' | ||
|
||
var msg = JSON.parse( | ||
'{"canId":166725416,"prio":2,"src":40,"dst":255,"pgn":126983,"direction":"R","time":"15:48:36.090","fields":{"Alert Type":"Warning","Alert Category":"Navigational","Alert System":20,"Alert ID":23480,"Data Source Network ID NAME":6458553273545042000,"Data Source Instance":0,"Data Source Index-Source":0,"Alert Occurrence Number":1,"Temporary Silence Status":"Not Temporary Silence","Acknowledge Status":"Acknowledged","Escalation Status":"Not Escalated","Temporary Silence Support":"Supported","Acknowledge Support":"Supported","Escalation Support":"Not Supported","Acknowledge Source Network ID NAME":1233993542451364400,"Trigger Condition":"Auto","Threshold Status":"Threshold Exceeded","Alert Priority":187,"Alert State":"Active"},"description":"Alert","timestamp":"2020-03-03T15:48:36.494Z"}' | ||
) | ||
var tree = mapper.toNested(msg, state) | ||
tree.should.have.nested.property('notifications.nmea.warning.navigational.20.23480.value') | ||
|
||
expect(tree.notifications.nmea.warning.navigational[20][23480].value).to.deep.include(value) | ||
|
||
var delta = mapper.toDelta(msg) | ||
delta.updates.length.should.equal(1) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
var chai = require('chai') | ||
chai.Should() | ||
chai.use(require('chai-things')) | ||
chai.use(require('@signalk/signalk-schema').chaiModule) | ||
var expect = chai.expect; | ||
|
||
const mapper = require('./testMapper') | ||
|
||
var state = {} | ||
|
||
describe('126985 alert text', function () { | ||
it('alert text converts', function () { | ||
mapper.toNested( | ||
JSON.parse( | ||
'{"canId":166725928,"prio":2,"src":40,"dst":255,"pgn":126985,"direction":"R","time":"15:52:04.346","fields":{"Alert Type":"Warning","Alert Category":"Navigational","Alert System":20,"Alert ID":23480,"Data Source Network ID NAME":6458553273545042000,"Data Source Instance":0,"Data Source Index-Source":0,"Alert Occurrence Number":1,"Language ID":"English (US)","Alert Text Description":"TEST: Temperature over 0"},"description":"Alert Text","timestamp":"2020-03-03T15:52:04.505Z"}' | ||
), | ||
state | ||
) | ||
|
||
var text = {"40":{"alerts":{"23480":{"languageId":"English (US)","locationTextDescription": "","textDescription":"TEST: Temperature over 0"}}}} | ||
expect(state).to.deep.include(text) | ||
}) | ||
}) |