From 8d518efd39d1aafebc5de6cb1bb00fc038db2113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teemu=20Heikkil=C3=A4?= Date: Sun, 5 Sep 2021 18:02:56 +0300 Subject: [PATCH 1/4] Create 65312.js --- pgns/65312.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 pgns/65312.js diff --git a/pgns/65312.js b/pgns/65312.js new file mode 100644 index 0000000..bab6899 --- /dev/null +++ b/pgns/65312.js @@ -0,0 +1,8 @@ +module.exports = [ + { + source: 'Signal Strength', + node: function(n2k){ + return `instruments.wireless.${n2k.src}.signalStrength` + } + } +] From 2fde9a69da90bc805b0d7e8b06c6d6fc4b143b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teemu=20Heikkil=C3=A4?= Date: Sun, 5 Sep 2021 19:16:47 +0300 Subject: [PATCH 2/4] Create 65309.js {"canId":486481152,"prio":7,"src":0,"dst":255,"pgn":65309,"time":"1628312401044;A;06:25:52.641","input":["1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Status":0,"Battery Status":78,"Battery Charge Status":10,"Reserved2":8388607},"description":"Navico: Wireless Battery Status","timestamp":"2021-09-05T14:43:06.818Z"} --- pgns/65309.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 pgns/65309.js diff --git a/pgns/65309.js b/pgns/65309.js new file mode 100644 index 0000000..022db56 --- /dev/null +++ b/pgns/65309.js @@ -0,0 +1,13 @@ +module.exports = [ + { + source: 'Battery Status', + node: function(n2k){ + return `electrical.batteries.wireless${n2k.src}.batteryStatus` + } + },{ + source: 'Battery Charge Status', + node: function(n2k){ + return `electrical.batteries.wireless${n2k.src}.batteryChargeStatus` + } + }, +] From 26bb435b786696d195b5957927319c311663b3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teemu=20Heikkil=C3=A4?= Date: Sun, 5 Sep 2021 20:16:02 +0300 Subject: [PATCH 3/4] Add B&G WS320 related PGNs --- bandg/65309.js | 18 ++++++++++++++ {pgns => bandg}/65312.js | 0 bandg/index.js | 5 ++++ n2kMapper.js | 1 + pgns/65309.js | 13 ---------- test/bandg.js | 53 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 bandg/65309.js rename {pgns => bandg}/65312.js (100%) create mode 100644 bandg/index.js delete mode 100644 pgns/65309.js create mode 100644 test/bandg.js diff --git a/bandg/65309.js b/bandg/65309.js new file mode 100644 index 0000000..31e70c4 --- /dev/null +++ b/bandg/65309.js @@ -0,0 +1,18 @@ +module.exports = [ + { + source: 'Battery Status', + node: function(n2k){ + return `instruments.wireless.${n2k.src}.batteryStatus` + } + },{ + source: 'Battery Charge Status', + node: function(n2k){ + return `instruments.wireless.${n2k.src}.batteryChargeStatus` + } + },{ + source: 'Status', + node: function(n2k){ + return `instruments.wireless.${n2k.src}.status` + } + }, +] diff --git a/pgns/65312.js b/bandg/65312.js similarity index 100% rename from pgns/65312.js rename to bandg/65312.js diff --git a/bandg/index.js b/bandg/index.js new file mode 100644 index 0000000..9beb348 --- /dev/null +++ b/bandg/index.js @@ -0,0 +1,5 @@ +module.exports = { + 65309: require('./65309.js'), + 65312: require('./65312.js'), +} + \ No newline at end of file diff --git a/n2kMapper.js b/n2kMapper.js index a89d57a..ce73f8c 100644 --- a/n2kMapper.js +++ b/n2kMapper.js @@ -14,6 +14,7 @@ Object.assign(n2kMappings, require('./raymarine')) Object.assign(n2kMappings, require('./maretron')) Object.assign(n2kMappings, require('./actisense')) Object.assign(n2kMappings, require('./digitalyacht')) +Object.assign(n2kMappings, require('./bandg')) function N2kMapper (options) { this.state = { } diff --git a/pgns/65309.js b/pgns/65309.js deleted file mode 100644 index 022db56..0000000 --- a/pgns/65309.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = [ - { - source: 'Battery Status', - node: function(n2k){ - return `electrical.batteries.wireless${n2k.src}.batteryStatus` - } - },{ - source: 'Battery Charge Status', - node: function(n2k){ - return `electrical.batteries.wireless${n2k.src}.batteryChargeStatus` - } - }, -] diff --git a/test/bandg.js b/test/bandg.js new file mode 100644 index 0000000..66993d2 --- /dev/null +++ b/test/bandg.js @@ -0,0 +1,53 @@ +const chai = require('chai') +chai.Should() +chai.use(require('chai-things')) +chai.use(require('@signalk/signalk-schema').chaiModule) + +const N2kMapper = require('../n2kMapper').N2kMapper +const toNested = require('./testMapper').toNested + +describe('B&G PGNs work', function () { + const n2kMapper = new N2kMapper() + + n2kMapper.toDelta({"canId":486481152,"prio":7,"src":0,"dst":255,"pgn":65309,"time":"1628312401044;A;06:25:52.641","input":["1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Status":0,"Battery Status":78,"Battery Charge Status":10,"Reserved2":8388607},"description":"Navico: Wireless Battery Status","timestamp":"2021-09-05T14:43:06.818Z"}) + + + it('65309 WS320 Battery status', function () { + var tree = toNested( + JSON.parse( + '{"canId":486481152,"prio":7,"src":0,"dst":255,"pgn":65309,"time":"1628312401044;A;06:25:52.641","input":["1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Status":0,"Battery Status":78,"Battery Charge Status":10,"Reserved2":8388607},"description":"Navico: Wireless Battery Status","timestamp":"2021-09-05T14:43:06.818Z"}', + ), + n2kMapper.state + ) + + tree.should.have.nested.property( + 'instruments.wireless.0.batteryStatus.value', + 78 + ) + tree.should.have.nested.property( + 'instruments.wireless.0.batteryChargeStatus.value', + 10 + ) + tree.should.have.nested.property( + 'instruments.wireless.0.status.value', + 0 + ) + }) + n2kMapper.toDelta({"canId":486481920,"prio":7,"src":0,"dst":255,"pgn":65312,"time":"1628312404394;A;06:25:56.008","input":["1628312404394;A;06:25:56.008 R 1CFF2000 13 99 00 2D 7F FF FF FF"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Unknown":0,"Signal Strength":45,"Reserved2":16777087},"description":"Navico: Wireless Signal Status","timestamp":"2021-09-05T14:43:06.823Z"}) + + it('65312 WS320 Signal status', function () { + var tree = toNested( + JSON.parse( + '{"canId":486481920,"prio":7,"src":0,"dst":255,"pgn":65312,"time":"1628312404394;A;06:25:56.008","input":["1628312404394;A;06:25:56.008 R 1CFF2000 13 99 00 2D 7F FF FF FF"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Unknown":0,"Signal Strength":45,"Reserved2":16777087},"description":"Navico: Wireless Signal Status","timestamp":"2021-09-05T14:43:06.823Z"}', + ), + n2kMapper.state + ) + + tree.should.have.nested.property( + 'instruments.wireless.0.signalStrength.value', + 45 + ) + }) + + +}) From 5b6bf8492780b4ab5aa7641880b5e9d98309aa8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teemu=20Heikkil=C3=A4?= Date: Sun, 5 Sep 2021 20:19:09 +0300 Subject: [PATCH 4/4] Format using npm format --- n2kMapper.js | 146 ++++++++++++++++++++++++++++---------------------- test/bandg.js | 51 ++++++++++++++---- 2 files changed, 123 insertions(+), 74 deletions(-) diff --git a/n2kMapper.js b/n2kMapper.js index ce73f8c..8197fb3 100644 --- a/n2kMapper.js +++ b/n2kMapper.js @@ -4,7 +4,7 @@ var debug = require('debug')('signalk:n2k-signalk') const toPgn = require('@canboat/canboatjs').toPgn const Uint64LE = require('int64-buffer').Uint64LE -require('util').inherits(N2kMapper, EventEmitter); +require('util').inherits(N2kMapper, EventEmitter) var n2kMappings = {} Object.assign(n2kMappings, require('./pgns')) @@ -17,39 +17,43 @@ Object.assign(n2kMappings, require('./digitalyacht')) Object.assign(n2kMappings, require('./bandg')) function N2kMapper (options) { - this.state = { } + this.state = {} this.unknownPGNs = {} this.customPgns = {} this.options = options || {} - - if ( this.options.onPropertyValues ) { + + if (this.options.onPropertyValues) { this.options.onPropertyValues('pgn-to-signalk', values => { - values.filter(v => v !== undefined).forEach(pv => { - Object.entries(pv.value).forEach(([pgnNumber, mappings]) => { - if ( n2kMappings[pgnNumber] && - !this.options.allowCustomPGNOverride ) { - console.error(`pgn ${pgnNumber} can't be overwritten`) - } else { - this.customPgns[pgnNumber] = mappings - debug('registered custom pgn %d by %s', pgnNumber, pv.setter) - } + values + .filter(v => v !== undefined) + .forEach(pv => { + Object.entries(pv.value).forEach(([pgnNumber, mappings]) => { + if ( + n2kMappings[pgnNumber] && + !this.options.allowCustomPGNOverride + ) { + console.error(`pgn ${pgnNumber} can't be overwritten`) + } else { + this.customPgns[pgnNumber] = mappings + debug('registered custom pgn %d by %s', pgnNumber, pv.setter) + } + }) }) - }) }) } } -N2kMapper.prototype.n2kOutIsAvailable = function(listener, event) { +N2kMapper.prototype.n2kOutIsAvailable = function (listener, event) { this.n2kOutEvent = event this.n2kListener = listener this.requestAllMeta() } -N2kMapper.prototype.requestMetaData = function(dst, pgn) { +N2kMapper.prototype.requestMetaData = function (dst, pgn) { const reqPgn = { - "pgn": 59904, - "dst": dst, - "PGN": pgn + pgn: 59904, + dst: dst, + PGN: pgn } debug(`requesting pgn ${pgn} from src ${dst}`) return new Promise((resolve, reject) => { @@ -60,64 +64,73 @@ N2kMapper.prototype.requestMetaData = function(dst, pgn) { }) } -N2kMapper.prototype.requestMetaPGNs = async function(dst, pgns) { - for ( let i = 0; i < pgns.length; i++ ) { +N2kMapper.prototype.requestMetaPGNs = async function (dst, pgns) { + for (let i = 0; i < pgns.length; i++) { await this.requestMetaData(dst, pgns[i]) } } -N2kMapper.prototype.checkSrcMetasAndRetry = function(src) { - if ( src !== "255" ) { +N2kMapper.prototype.checkSrcMetasAndRetry = function (src) { + if (src !== '255') { const neededPGNs = Object.keys(metaPGNs).filter(pgn => { - return !this.state[src].metaPGNsReceived || + return ( + !this.state[src].metaPGNsReceived || !this.state[src].metaPGNsReceived[pgn] + ) }) - if ( neededPGNs.length > 0 ) { + if (neededPGNs.length > 0) { debug('did not get meta pgns %j for src %d', neededPGNs, src) - this.requestMetaPGNs(src, neededPGNs) - .then(() => { - neededPGNs.forEach(pgn => { - if (!this.state[src].metaPGNsReceived || - !this.state[src].metaPGNsReceived[pgn]) { - debug(`did not get meta pgn ${pgn} for src ${src}`) - this.emit('n2kSourceMetadataTimeout', pgn, src) - } - }) + this.requestMetaPGNs(src, neededPGNs).then(() => { + neededPGNs.forEach(pgn => { + if ( + !this.state[src].metaPGNsReceived || + !this.state[src].metaPGNsReceived[pgn] + ) { + debug(`did not get meta pgn ${pgn} for src ${src}`) + this.emit('n2kSourceMetadataTimeout', pgn, src) + } }) + }) } } } -N2kMapper.prototype.requestAllMeta = function() { - this.requestMetaPGNs(255, Object.keys(metaPGNs)) - .then(() => { - Object.keys(this.state).forEach(src => this.checkSrcMetasAndRetry(src)) - }) +N2kMapper.prototype.requestAllMeta = function () { + this.requestMetaPGNs(255, Object.keys(metaPGNs)).then(() => { + Object.keys(this.state).forEach(src => this.checkSrcMetasAndRetry(src)) + }) } -N2kMapper.prototype.toDelta = function(n2k) { - if ( metaPGNs[n2k.pgn] ) { +N2kMapper.prototype.toDelta = function (n2k) { + if (metaPGNs[n2k.pgn]) { const meta = metaPGNs[n2k.pgn](n2k) - if ( ! this.state[n2k.src] ) { + if (!this.state[n2k.src]) { this.state[n2k.src] = {} } - if ( !this.state[n2k.src].metaPGNsReceived ) { + if (!this.state[n2k.src].metaPGNsReceived) { this.state[n2k.src].metaPGNsReceived = {} } - if ( n2k.pgn === 60928 ) { + if (n2k.pgn === 60928) { const canName = new Uint64LE(toPgn(n2k)).toString(16) - if ( ! this.state[n2k.src] ) { + if (!this.state[n2k.src]) { this.state[n2k.src] = {} - } else if ( this.state[n2k.src].canName && this.state[n2k.src].canName != canName ) { + } else if ( + this.state[n2k.src].canName && + this.state[n2k.src].canName != canName + ) { // clear out any existing state since the src addresses have changed - this.emit('n2kSourceChanged', n2k.src, this.state[n2k.src].canName, canName) + this.emit( + 'n2kSourceChanged', + n2k.src, + this.state[n2k.src].canName, + canName + ) this.state[n2k.src] = {} - this.requestMetaData(n2k.src, 126996) - .then(() => { - return this.requestMetaData(n2k.src, 126998) - }) + this.requestMetaData(n2k.src, 126996).then(() => { + return this.requestMetaData(n2k.src, 126998) + }) } this.state[n2k.src].deviceInstance = meta.deviceInstance meta.canName = canName @@ -125,16 +138,18 @@ N2kMapper.prototype.toDelta = function(n2k) { } this.state[n2k.src].metaPGNsReceived[n2k.pgn] = Date.now() - + this.emit('n2kSourceMetadata', n2k, meta) } else { - if ( !n2kMappings[n2k.pgn] ) { - if ( !this.unknownPGNs[n2k.src] ) { + if (!n2kMappings[n2k.pgn]) { + if (!this.unknownPGNs[n2k.src]) { this.unknownPGNs[n2k.src] = {} } - if ( !this.unknownPGNs[n2k.src][n2k.pgn] ) { + if (!this.unknownPGNs[n2k.src][n2k.pgn]) { this.unknownPGNs[n2k.src][n2k.pgn] = n2k - this.emit('n2kSourceMetadata', n2k, { unknownPGNs: this.unknownPGNs[n2k.src] }) + this.emit('n2kSourceMetadata', n2k, { + unknownPGNs: this.unknownPGNs[n2k.src] + }) } } return toDelta(n2k, this.state, this.customPgns) @@ -145,7 +160,10 @@ var toDelta = function (n2k, state, customPgns = {}) { try { var theMappings, customMappings - theMappings = [ ...customPgns[n2k.pgn] || [], ...n2kMappings[n2k.pgn] || []] + theMappings = [ + ...(customPgns[n2k.pgn] || []), + ...(n2kMappings[n2k.pgn] || []) + ] var src_state if (state) { @@ -172,10 +190,10 @@ var toDelta = function (n2k, state, customPgns = {}) { } ] } - if ( src_state && src_state.canName ) { + if (src_state && src_state.canName) { result.updates[0].source.canName = src_state.canName } - if ( src_state && typeof src_state.deviceInstance !== 'undefined' ) { + if (src_state && typeof src_state.deviceInstance !== 'undefined') { result.updates[0].source.deviceInstance = src_state.deviceInstance } if ( @@ -330,7 +348,7 @@ function addAsNested (pathValue, source, timestamp, result) { } const metaPGNs = { - 60928: (n2k) => { + 60928: n2k => { return { uniqueId: n2k.fields['Unique Number'], manufacturerName: n2k.fields['Manufacturer Code'], @@ -339,10 +357,12 @@ const metaPGNs = { deviceInstanceLower: n2k.fields['Device Instance Lower'], deviceInstanceUpper: n2k.fields['Device Instance Upper'], systemInstance: n2k.fields['System Instance'], - deviceInstance: (n2k.fields['Device Instance Upper'] << 3) | n2k.fields['Device Instance Lower'] + deviceInstance: + (n2k.fields['Device Instance Upper'] << 3) | + n2k.fields['Device Instance Lower'] } }, - 126998: (n2k) => { + 126998: n2k => { return { installationNote1: n2k.fields['Installation Description #1'], installationNote2: n2k.fields['Installation Description #2'], @@ -350,7 +370,7 @@ const metaPGNs = { manufacturerInfo: n2k.fields['Manufacturer Information'] } }, - 126996: (n2k) => { + 126996: n2k => { return { productName: n2k.fields['Model ID'], hardwareVersion: n2k.fields['Model Version'], diff --git a/test/bandg.js b/test/bandg.js index 66993d2..b5c04e6 100644 --- a/test/bandg.js +++ b/test/bandg.js @@ -9,13 +9,30 @@ const toNested = require('./testMapper').toNested describe('B&G PGNs work', function () { const n2kMapper = new N2kMapper() - n2kMapper.toDelta({"canId":486481152,"prio":7,"src":0,"dst":255,"pgn":65309,"time":"1628312401044;A;06:25:52.641","input":["1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Status":0,"Battery Status":78,"Battery Charge Status":10,"Reserved2":8388607},"description":"Navico: Wireless Battery Status","timestamp":"2021-09-05T14:43:06.818Z"}) - + n2kMapper.toDelta({ + canId: 486481152, + prio: 7, + src: 0, + dst: 255, + pgn: 65309, + time: '1628312401044;A;06:25:52.641', + input: ['1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F'], + fields: { + 'Manufacturer Code': 'Navico', + 'Industry Code': 'Marine Industry', + Status: 0, + 'Battery Status': 78, + 'Battery Charge Status': 10, + Reserved2: 8388607 + }, + description: 'Navico: Wireless Battery Status', + timestamp: '2021-09-05T14:43:06.818Z' + }) it('65309 WS320 Battery status', function () { var tree = toNested( JSON.parse( - '{"canId":486481152,"prio":7,"src":0,"dst":255,"pgn":65309,"time":"1628312401044;A;06:25:52.641","input":["1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Status":0,"Battery Status":78,"Battery Charge Status":10,"Reserved2":8388607},"description":"Navico: Wireless Battery Status","timestamp":"2021-09-05T14:43:06.818Z"}', + '{"canId":486481152,"prio":7,"src":0,"dst":255,"pgn":65309,"time":"1628312401044;A;06:25:52.641","input":["1628312401044;A;06:25:52.641 R 1CFF1D00 13 99 00 4E 0A FF FF 7F"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Status":0,"Battery Status":78,"Battery Charge Status":10,"Reserved2":8388607},"description":"Navico: Wireless Battery Status","timestamp":"2021-09-05T14:43:06.818Z"}' ), n2kMapper.state ) @@ -28,17 +45,31 @@ describe('B&G PGNs work', function () { 'instruments.wireless.0.batteryChargeStatus.value', 10 ) - tree.should.have.nested.property( - 'instruments.wireless.0.status.value', - 0 - ) + tree.should.have.nested.property('instruments.wireless.0.status.value', 0) + }) + n2kMapper.toDelta({ + canId: 486481920, + prio: 7, + src: 0, + dst: 255, + pgn: 65312, + time: '1628312404394;A;06:25:56.008', + input: ['1628312404394;A;06:25:56.008 R 1CFF2000 13 99 00 2D 7F FF FF FF'], + fields: { + 'Manufacturer Code': 'Navico', + 'Industry Code': 'Marine Industry', + Unknown: 0, + 'Signal Strength': 45, + Reserved2: 16777087 + }, + description: 'Navico: Wireless Signal Status', + timestamp: '2021-09-05T14:43:06.823Z' }) - n2kMapper.toDelta({"canId":486481920,"prio":7,"src":0,"dst":255,"pgn":65312,"time":"1628312404394;A;06:25:56.008","input":["1628312404394;A;06:25:56.008 R 1CFF2000 13 99 00 2D 7F FF FF FF"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Unknown":0,"Signal Strength":45,"Reserved2":16777087},"description":"Navico: Wireless Signal Status","timestamp":"2021-09-05T14:43:06.823Z"}) it('65312 WS320 Signal status', function () { var tree = toNested( JSON.parse( - '{"canId":486481920,"prio":7,"src":0,"dst":255,"pgn":65312,"time":"1628312404394;A;06:25:56.008","input":["1628312404394;A;06:25:56.008 R 1CFF2000 13 99 00 2D 7F FF FF FF"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Unknown":0,"Signal Strength":45,"Reserved2":16777087},"description":"Navico: Wireless Signal Status","timestamp":"2021-09-05T14:43:06.823Z"}', + '{"canId":486481920,"prio":7,"src":0,"dst":255,"pgn":65312,"time":"1628312404394;A;06:25:56.008","input":["1628312404394;A;06:25:56.008 R 1CFF2000 13 99 00 2D 7F FF FF FF"],"fields":{"Manufacturer Code":"Navico","Industry Code":"Marine Industry","Unknown":0,"Signal Strength":45,"Reserved2":16777087},"description":"Navico: Wireless Signal Status","timestamp":"2021-09-05T14:43:06.823Z"}' ), n2kMapper.state ) @@ -48,6 +79,4 @@ describe('B&G PGNs work', function () { 45 ) }) - - })