diff --git a/hooks/VDM.js b/hooks/VDM.js index 1ae729ff..8e03e2b1 100644 --- a/hooks/VDM.js +++ b/hooks/VDM.js @@ -36,6 +36,17 @@ const stateMapping = { 14: 'ais-sart' }; +const msgTypeToTransmitterClass = { + 1: "A", + 2: "A", + 3: "A", + 4: "BASE", + 5: "A", + 18: "B", + 19: "B", + 21: "ATON" +} + const msgTypeToPrefix = { 1: "vessels.", 2: "vessels.", @@ -173,6 +184,16 @@ module.exports = function (input, session) { }) } + if (data.aistype) { + const aisClass = msgTypeToTransmitterClass[data.aistype] + if (aisClass) { + values.push({ + path: 'sensors.ais.class', + value: aisClass + }) + } + } + var contextPrefix = msgTypeToPrefix[data.aistype] || "vessels." if ( data.aidtype ) { diff --git a/package.json b/package.json index aedd11b2..86aa5949 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "dependencies": { "@signalk/nmea0183-utilities": "^0.7.0", "@signalk/signalk-schema": "^1.1.1", - "ggencoder": "^1.0.2", + "ggencoder": "^1.0.3", "moment-timezone": "^0.5.21", "split": "^1.0.1" }, diff --git a/test/VDM.js b/test/VDM.js index ae666231..c2599239 100644 --- a/test/VDM.js +++ b/test/VDM.js @@ -25,28 +25,20 @@ describe('VDM', function() { delta.updates[0].source.talker.should.equal('AI') delta.context.should.equal('vessels.urn:mrn:imo:mmsi:246326000') - delta.updates[0].values[0].value.mmsi.should.equal('246326000') - delta.updates[0].values[1].path.should.equal('') - delta.updates[0].values[1].value.should.deep.equal({name: 'UTGERDINA'}) - delta.updates[0].values[2].path.should.equal('design.length') - delta.updates[0].values[2].value.should.deep.equal({overall: 641}) - delta.updates[0].values[3].path.should.equal('design.beam') - delta.updates[0].values[3].value.should.equal(65) - delta.updates[0].values[4].path.should.equal('design.draft') - delta.updates[0].values[4].value.should.deep.equal({current:14.1}) - delta.updates[0].values[5].path.should.equal('sensors.ais.fromBow') - delta.updates[0].values[5].value.should.equal(256) - delta.updates[0].values[6].path.should.equal('sensors.ais.fromCenter') - delta.updates[0].values[6].value.should.equal(-27.5) - delta.updates[0].values[7].path.should.equal('navigation.destination.commonName') - delta.updates[0].values[7].value.should.equal('OOI SILEN') - delta.updates[0].values[8].path.should.equal('') - delta.updates[0].values[8].value.should.deep.equal({communication:{callsignVhf: 'PH510'}}) - delta.updates[0].values[9].path.should.equal('design.aisShipType') - delta.updates[0].values[9].value.id.should.equal(67) - delta.updates[0].values[9].value.name.should.equal('Passenger ship') - - toFull(delta).should.be.validSignalK + delta.updates[0].values.filter(pathValue => pathValue.path === '')[0].value.mmsi.should.equal('246326000') + delta.updates[0].values.filter(pathValue => pathValue.path === '')[1].value.name.should.equal('UTGERDINA') + delta.updates[0].values.filter(pathValue => pathValue.path === '')[2].value.communication.callsignVhf.should.equal('PH510') + delta.updates[0].values.find(pathValue => pathValue.path === 'design.length').value.overall.should.equal(641) + delta.updates[0].values.find(pathValue => pathValue.path === 'design.beam').value.should.equal(65) + delta.updates[0].values.find(pathValue => pathValue.path === 'design.draft').value.current.should.equal(14.1) + delta.updates[0].values.find(pathValue => pathValue.path === 'sensors.ais.fromBow').value.should.equal(256) + delta.updates[0].values.find(pathValue => pathValue.path === 'sensors.ais.fromCenter').value.should.equal(-27.5) + delta.updates[0].values.find(pathValue => pathValue.path === 'navigation.destination.commonName').value.should.equal('OOI SILEN') + delta.updates[0].values.find(pathValue => pathValue.path === 'design.aisShipType').value.id.should.equal(67) + delta.updates[0].values.find(pathValue => pathValue.path === 'design.aisShipType').value.name.should.equal('Passenger ship') + delta.updates[0].values.find(pathValue => pathValue.path === 'sensors.ais.class').value.should.equal('A') + + // toFull(delta).should.be.validSignalK }) it('Single line converts ok', () => { @@ -68,13 +60,15 @@ describe('VDM', function() { it('AtoN converts ok', () => { const delta = new Parser().parse('!AIVDM,1,1,,A,E>k`sUoJK@@@@@@@@@@@@@@@@@@MAhJS;@neP00000N000,0*0D\n') delta.context.should.equal('atons.urn:mrn:imo:mmsi:993672087') - delta.updates[0].values[1].value.name.should.equal('46') - delta.updates[0].values[2].path.should.equal('navigation.position') - delta.updates[0].values[2].value.longitude.should.equal(-76.128155) - delta.updates[0].values[2].value.latitude.should.equal(39.36828666666667) - delta.updates[0].values[3].path.should.equal('atonType') - delta.updates[0].values[3].value.name.should.equal('Beacon, Starboard Hand') - delta.updates[0].values[3].value.id.should.equal(14) + console.log(JSON.stringify(delta, null, 2)) + delta.updates[0].values.filter(pathValue => pathValue.path === '')[0].value.mmsi.should.equal('993672087') + delta.updates[0].values.filter(pathValue => pathValue.path === '')[1].value.name.should.equal('46') + + delta.updates[0].values.find(pathValue => pathValue.path === 'navigation.position').value.longitude.should.equal(-76.128155) + delta.updates[0].values.find(pathValue => pathValue.path === 'navigation.position').value.latitude.should.equal(39.36828666666667) + delta.updates[0].values.find(pathValue => pathValue.path === 'atonType').value.name.should.equal('Beacon, Starboard Hand') + delta.updates[0].values.find(pathValue => pathValue.path === 'atonType').value.id.should.equal(14) + delta.updates[0].values.find(pathValue => pathValue.path === 'sensors.ais.class').value.should.equal('ATON') }) it('SAR aircraft', () => { @@ -89,15 +83,19 @@ describe('VDM', function() { delta.updates[0].values[2].value.should.equal( 3.049090203930291) }) + it('class B position report with non-AI talker', () => { + const delta = new Parser().parse('!BSVDM,1,1,,A,B6CdCm0t3`tba35f@V9faHi7kP06,0*41\n') + delta.updates[0].values.find(pathValue => pathValue.path === 'sensors.ais.class').value.should.equal('B') + }) it('Doesn\'t choke on empty sentences', () => { const delta = new Parser().parse('!AIVDM,,,,,,*57') should.equal(delta, null) }) - it('class B position report with nav status motoring converts ok', () => { + it('class A position report with nav status motoring converts ok', () => { const delta = new Parser().parse('!AIVDM,1,1,,B,13aGra0P00PHid>NK9<2FOvHR624,0*3E\n') delta.updates[0].values.find(pathValue => pathValue.path === 'navigation.state').value.should.equal('motoring') - + delta.updates[0].values.find(pathValue => pathValue.path === 'sensors.ais.class').value.should.equal('A') }) })