Skip to content

Commit

Permalink
feature: adds support for alert PGNs 126983 and 126985 (#173)
Browse files Browse the repository at this point in the history
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
jncarter123 authored Mar 7, 2020
1 parent 6793b21 commit 49f9896
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 0 deletions.
86 changes: 86 additions & 0 deletions pgns/126983.js
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']]
)
}
}]
24 changes: 24 additions & 0 deletions pgns/126985.js
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'
}]
2 changes: 2 additions & 0 deletions pgns/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
module.exports = {
126983: require('./126983.js'),
126985: require('./126985.js'),
126992: require('./126992.js'),
127245: require('./127245.js'),
127250: require('./127250.js'),
Expand Down
96 changes: 96 additions & 0 deletions test/126983_alert.js
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)
})
})
23 changes: 23 additions & 0 deletions test/126985_alert_text.js
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)
})
})

0 comments on commit 49f9896

Please sign in to comment.