@signalk/nmea0183-signalk
Version:
A node.js/javascript parser for NMEA0183 sentences. Sentences are parsed to Signal K format.
366 lines (331 loc) • 12.9 kB
JavaScript
/**
* Copyright 2016 Signal K and contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const seatalkHooks = require('../hooks/seatalk')
var utils = require('@signalk/nmea0183-utilities')
const chai = require('chai')
const Parser = require('../lib')
const depthData = '00,02,41,22,22'
const apparentWindAngleData = '10,01,01,10'
const apparentWindSpeedData = '11,01,01,02'
const speedThroughWaterData = '20,01,22,11'
const tripMileageData = '21,02,32,34,02'
const logData = '22,02,33,56,00'
const tripAndLogData = '25,44,65,54,43,32,02'
const averageSpeedThroughWaterData = '26,04,12,11,10,11,21'
const waterTemperatureData = '27,01,01,01'
const latitudeData = '50,22,21,01'
const longitudeData = '51,21,21,01'
const sogData = '52,01,02,00'
const cogData = '53,10,22'
const timeTag = '\\s:test,c:1438489697*29\\'
const timeData = '54,21,22,11' //using tag to force timestamp
const dateTag = '\\s:test,c:1438489697*29\\'
const dateData = '56,31,23,18' //using tag to force timestamp
const satInfoData = '57,70,94'
const headingData = '84,B6,10,00,00,00,00,00,00'
const standbyData = '84,E6,15,00,00,00,00,00,08'
const autoData = '84,56,5E,79,02,00,00,00,08'
const windData = '84,06,00,00,04,00,00,00,00'
const routeData = '84,06,00,00,08,00,00,00,00'
const rudderData = '84,06,00,00,08,00,FE,00,00'
const compassVariationData = '99,00,43'
const heading_nineCData = '9C,51,1E,00'
const empty_nineCData = '9C,,,'
const empty_eightFourData = '84,,,,,,,,'
const should = chai.Should()
chai.use(require('chai-things'))
describe('seatalk', () => {
;['$PSMDST,', '$PSMDST,R,', '$STALK,'].forEach((prefix) => {
it(`${prefix} 0x00 depth converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${depthData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'environment.depth.belowTransducer'
)
delta.updates[0].values[0].value.should.be.closeTo(266.33424, 0.0005)
})
it(`${prefix} 0x10 AWA converted`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${apparentWindAngleData}`
)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'environment.wind.angleApparent'
)
delta.updates[0].values[0].value.should.be.closeTo(
2.373647783254262,
0.0005
)
})
it(`${prefix} 0x11 AWS converted`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${apparentWindSpeedData}`
)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'environment.wind.speedApparent'
)
delta.updates[0].values[0].value.should.be.closeTo(
0.6173334897244841,
0.0005
)
})
it(`${prefix} 0x20 STW converted`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${speedThroughWaterData}`
)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.speedThroughWater'
)
delta.updates[0].values[0].value.should.be.closeTo(
2.6236673313290573,
0.0005
)
})
it(`${prefix} 0x21 Trip converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${tripMileageData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.trip'
)
delta.updates[0].values[0].value.should.be.closeTo(
2674917.68225763,
0.0005
)
})
it(`${prefix} 0x22 Total log converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${logData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.log'
)
delta.updates[0].values[0].value.should.be.closeTo(4086808.4, 0.5)
})
it(`${prefix} 0x25 trip and log converted 2`, () => {
const fullSentence = utils.appendChecksum(`${prefix}25,14,4C,BF,00,00,00}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.log'
)
delta.updates[0].values[1].value.should.be.closeTo(utils.transform(11450.8, 'nm', 'm'), 0.5)
})
it(`${prefix} 0x25 trip and log converted 1`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${tripAndLogData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.trip'
)
delta.updates[0].values[0].value.should.be.closeTo(2665750.28, 0.5)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.log'
)
delta.updates[0].values[1].value.should.be.closeTo(52550314.8, 0.5)
})
it(`${prefix} 0x26 STW converted`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${averageSpeedThroughWaterData}`
)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.averageSpeedThroughWater'
)
delta.updates[0].values[0].value.should.be.closeTo(22.47, 0.5)
})
it(`${prefix} 0x27 Water temperature converted`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${waterTemperatureData}`
)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'environment.water.temperature'
)
delta.updates[0].values[0].value.should.be.closeTo(288.9, 0.5)
})
const parser = new Parser()
it(`${prefix} 0x50 Latitude and 0x51 Longitude converted`, () => {
var fullSentence = utils.appendChecksum(`${prefix}${latitudeData}`)
var delta = parser.parse(fullSentence)
fullSentence = utils.appendChecksum(`${prefix}${longitudeData}`)
delta = parser.parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.position'
)
delta.updates[0].values[0].value['latitude'].should.be.closeTo(33, 0.5)
delta.updates[0].values[0].value['longitude'].should.be.closeTo(-33, 0.5)
})
it(`${prefix} 0x52 SOG converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${sogData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.speedOverGround'
)
delta.updates[0].values[0].value.should.be.closeTo(0.103, 0.005)
})
it(`${prefix} 0x53 COG converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${cogData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.courseOverGroundMagnetic'
)
delta.updates[0].values[0].value.should.be.closeTo(2.7576, 0.005)
})
it(`${prefix} 0x54 time disabled`, () => {
const fullSentence =
timeTag + utils.appendChecksum(`${prefix}${timeData}`)
const delta = parser.parse(fullSentence)
})
it(`${prefix} 0x56 date disabled`, () => {
const fullSentence =
dateTag + utils.appendChecksum(`${prefix}${dateData}`)
const delta = parser.parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.datetime'
)
delta.updates[0].values[0].value.should.equal('2024-04-04T17:08:34.000Z')
})
it(`${prefix} 0x57 satelite info converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${satInfoData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.gnss.satellites'
)
delta.updates[0].values[0].value.should.equal(7)
})
it(`${prefix} 0x84 heading converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${headingData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.headingMagnetic'
)
delta.updates[0].values[0].value.should.be.closeTo(
5.305800926062761,
0.0005
)
})
it(`${prefix} 0x84 ap mode: standby converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${standbyData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'steering.autopilot.state'
)
delta.updates[0].values[1].value.should.equal('standby')
})
it(`${prefix} 0x84 ap mode: auto converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${autoData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'steering.autopilot.target.headingMagnetic'
)
delta.updates[0].values[1].value.should.be.closeTo(
2.626720524251466,
0.0005
)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'steering.autopilot.state'
)
delta.updates[0].values[2].value.should.equal('auto')
})
it(`${prefix} 0x84 ap mode: wind converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${windData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'steering.autopilot.state'
)
delta.updates[0].values[0].value.should.equal('wind')
})
it(`${prefix} 0x84 ap mode: route converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${routeData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'steering.autopilot.state'
)
delta.updates[0].values[0].value.should.equal('route')
})
it(`${prefix} 0x84 rudder angle converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${rudderData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'steering.rudderAngle'
)
delta.updates[0].values[0].value.should.be.closeTo(
-0.03490658503988659,
0.0005
)
})
it(`${prefix} 0x99 compass variation converted`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${compassVariationData}`
)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.magneticVariation'
)
delta.updates[0].values[0].value.should.be.closeTo(
1.0646508439596323,
0.0005
)
})
it(`${prefix} 0x9C ap target heading converted`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${heading_nineCData}`)
const delta = new Parser().parse(fullSentence)
delta.updates[0].values.should.contain.an.item.with.property(
'path',
'navigation.headingMagnetic'
)
delta.updates[0].values[0].value.should.be.closeTo(
2.6529004630313806,
0.0005
)
})
it(`${prefix} Doesn\'t choke on empty 0x9C sentences`, () => {
const fullSentence = utils.appendChecksum(`${prefix}${empty_nineCData}`)
const delta = new Parser().parse(fullSentence)
should.equal(delta, null)
})
it(`${prefix} Doesn\'t choke on empty 0x84 sentences`, () => {
const fullSentence = utils.appendChecksum(
`${prefix}${empty_eightFourData}`
)
const delta = new Parser().parse(fullSentence)
should.equal(delta, null)
})
})
})