From 8ca5e9dac8d65ddc20eaa38c95dc61fc17bba791 Mon Sep 17 00:00:00 2001 From: Peter Bergander Date: Sat, 22 Aug 2020 11:29:09 +0100 Subject: [PATCH 01/11] added MTA - Mean Temperature of Air; not recommended for new designs; sent by NKE Multigraphic --- README.md | 1 + hooks/MTA.js | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ hooks/index.js | 1 + test/MTA.js | 32 +++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 hooks/MTA.js create mode 100644 test/MTA.js diff --git a/README.md b/README.md index c0cf4f0e..5ce6a07c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [HSC - Heading Steering Command](https://www.tronico.fi/OH6NT/docs/NMEA0183.pdf) - KEP - NKE Performance data - [MDA - Meteorological Composite](https://gpsd.gitlab.io/gpsd/NMEA.html#_mda_meteorilogical_composite) +- [MTA - Mean Temperature of Air](https://www.nmea.org/Assets/100108_nmea_0183_sentences_not_recommended_for_new_designs.pdf) - [MTW - Mean Temperature of Water](https://gpsd.gitlab.io/gpsd/NMEA.html#_mtw_mean_temperature_of_water) - [MWV - Wind Speed and Angle](https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle) - [RMB - Recommended Minimum Navigation Information](https://gpsd.gitlab.io/gpsd/NMEA.html#_rmb_recommended_minimum_navigation_information) diff --git a/hooks/MTA.js b/hooks/MTA.js new file mode 100644 index 00000000..f0e437d2 --- /dev/null +++ b/hooks/MTA.js @@ -0,0 +1,55 @@ +/** + * 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. + */ + +'use strict' + + const utils = require('@signalk/nmea0183-utilities') + + /* + * MTA - Mean Temperature of Air + * + * 0 1 2 + * | | | + * $--MTA,x.x,C*hh + * + * Field Number: + * 0. Degrees + * 1. Unit of Measurement, Celcius + * 2. Checksum + * + */ + +module.exports = function (input) { + const { id, sentence, parts, tags } = input + + const delta = { + updates: [ + { + source: tags.source, + timestamp: tags.timestamp, + values: [ + { + path: 'environment.air.temperature', + value: utils.transform(utils.float(parts[0]), 'c', 'k') + //returns raw value, no transformation done + } + ] + } + ], + } + + return delta +} diff --git a/hooks/index.js b/hooks/index.js index d0c68f21..c7fa9c84 100644 --- a/hooks/index.js +++ b/hooks/index.js @@ -14,6 +14,7 @@ module.exports = { 'PBVE': require('./proprietary/PBVE.js'), 'PNKEP': require('./proprietary/PNKEP.js'), 'MDA': require('./MDA.js'), + 'MTA': require('./MTA.js'), 'MTW': require('./MTW.js'), 'MWV': require('./MWV.js'), 'RMB': require('./RMB.js'), diff --git a/test/MTA.js b/test/MTA.js new file mode 100644 index 00000000..0a27b517 --- /dev/null +++ b/test/MTA.js @@ -0,0 +1,32 @@ +/** + * 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. + */ + +'use strict' + +const Parser = require('../lib') +const chai = require('chai') + +chai.Should() +chai.use(require('chai-things')) + +describe('MTA', () => { + it('Converts OK using individual parser', () => { + const delta = new Parser().parse('$IIMTA,26.,C*31') + + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.air.temperature') + delta.updates[0].values[0].value.should.be.closeTo(299.15, 0.005) + }) +}) From 55eb49c8194880a867d4aad4803e13b64027b560 Mon Sep 17 00:00:00 2001 From: Peter Bergander Date: Sat, 22 Aug 2020 14:44:48 +0100 Subject: [PATCH 02/11] added MWD - Wind Direction and Speed; sent by NKE Multigraphic --- README.md | 1 + hooks/MWD.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ hooks/index.js | 1 + test/MWD.js | 36 +++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 hooks/MWD.js create mode 100644 test/MWD.js diff --git a/README.md b/README.md index 5ce6a07c..05f4c38a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ - [MDA - Meteorological Composite](https://gpsd.gitlab.io/gpsd/NMEA.html#_mda_meteorilogical_composite) - [MTA - Mean Temperature of Air](https://www.nmea.org/Assets/100108_nmea_0183_sentences_not_recommended_for_new_designs.pdf) - [MTW - Mean Temperature of Water](https://gpsd.gitlab.io/gpsd/NMEA.html#_mtw_mean_temperature_of_water) +- [MWD - Wind Speed and Direction](https://lists.nongnu.org/archive/html/gpsd-dev/2012-04/msg00048.html) - [MWV - Wind Speed and Angle](https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle) - [RMB - Recommended Minimum Navigation Information](https://gpsd.gitlab.io/gpsd/NMEA.html#_rmb_recommended_minimum_navigation_information) - [RMC - Recommended Minimum Navigation Information](https://gpsd.gitlab.io/gpsd/NMEA.html#_rmc_recommended_minimum_navigation_information) diff --git a/hooks/MWD.js b/hooks/MWD.js new file mode 100644 index 00000000..b3b9f440 --- /dev/null +++ b/hooks/MWD.js @@ -0,0 +1,71 @@ +'use strict' + +/** + * Copyright 2016 Signal K and Fabian Tollenaar . + * + * 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 debug = require('debug')('signalk-parser-nmea0183/MWD') +const utils = require('@signalk/nmea0183-utilities') + +/* + * $WIMWD,<0>,<1>,<2>,<3>,<4>,<5>,<6>,<7>*hh + * + * NMEA 0183 standard Wind Direction and Speed, with respect to north. + * + * <0> Wind direction, 0.0 to 359.9 degrees True, to the nearest 0.1 degree + * <1> T = True + * <2> Wind direction, 0.0 to 359.9 degrees Magnetic, to the nearest 0.1 degree + * <3> M = Magnetic + * <4> Wind speed, knots, to the nearest 0.1 knot. + * <5> N = Knots + * <6> Wind speed, meters/second, to the nearest 0.1 m/s. + * <7> M = Meters/second + */ + +module.exports = function(input) { + const { id, sentence, parts, tags } = input + var pathValues = [] + + if(parts[0] != ''){ + pathValues.push({ + 'path': 'environment.wind.directionTrue', + 'value': utils.transform(utils.float(parts[0]), 'deg', 'rad') + }) + } + if(parts[2] != ''){ + pathValues.push({ + 'path': 'environment.wind.directionMagnetic', + 'value': utils.transform(utils.float(parts[2]), 'deg', 'rad') + }) + } + if(parts[4] != ''){ + pathValues.push({ + 'path': 'environment.wind.speedTrue', + 'value': utils.transform(utils.float(parts[4]), 'knots', 'ms') + }) + } + + const delta = { + updates: [ + { + source: tags.source, + timestamp: tags.timestamp, + values: pathValues + } + ], + } + + return delta +} diff --git a/hooks/index.js b/hooks/index.js index c7fa9c84..f51e8e2c 100644 --- a/hooks/index.js +++ b/hooks/index.js @@ -16,6 +16,7 @@ module.exports = { 'MDA': require('./MDA.js'), 'MTA': require('./MTA.js'), 'MTW': require('./MTW.js'), + 'MWD': require('./MWD.js'), 'MWV': require('./MWV.js'), 'RMB': require('./RMB.js'), 'RMC': require('./RMC.js'), diff --git a/test/MWD.js b/test/MWD.js new file mode 100644 index 00000000..d56184e5 --- /dev/null +++ b/test/MWD.js @@ -0,0 +1,36 @@ +/** + * 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. + */ + +'use strict' + +const Parser = require('../lib') +const chai = require('chai') +const should = chai.Should() + +chai.use(require('chai-things')) + +describe('MWD', () => { + + it('speed & direction data', () => { + const delta = new Parser().parse('$IIMWD,,,046.,M,10.1,N,05.2,M*0B') + + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.speedTrue') + delta.updates[0].values[1].value.should.be.closeTo(5.19585, 0.00005) + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.directionMagnetic') + delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) + }) + +}) From 5b6469931d75402142914d26a4f8ca4ea827c02a Mon Sep 17 00:00:00 2001 From: Peter Bergander Date: Sat, 22 Aug 2020 14:49:33 +0100 Subject: [PATCH 03/11] changed SignalK key to environment.outside.temperature --- hooks/MTA.js | 2 +- test/MTA.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hooks/MTA.js b/hooks/MTA.js index f0e437d2..9a118f64 100644 --- a/hooks/MTA.js +++ b/hooks/MTA.js @@ -42,7 +42,7 @@ module.exports = function (input) { timestamp: tags.timestamp, values: [ { - path: 'environment.air.temperature', + path: 'environment.outside.temperature', value: utils.transform(utils.float(parts[0]), 'c', 'k') //returns raw value, no transformation done } diff --git a/test/MTA.js b/test/MTA.js index 0a27b517..0fe24e01 100644 --- a/test/MTA.js +++ b/test/MTA.js @@ -26,7 +26,7 @@ describe('MTA', () => { it('Converts OK using individual parser', () => { const delta = new Parser().parse('$IIMTA,26.,C*31') - delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.air.temperature') + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.outside.temperature') delta.updates[0].values[0].value.should.be.closeTo(299.15, 0.005) }) }) From feb59d33000ef2bb0cff25b75042866689b060c9 Mon Sep 17 00:00:00 2001 From: Peter Bergander Date: Sat, 22 Aug 2020 18:50:12 +0100 Subject: [PATCH 04/11] added VWT - True Wind Angle and Speed; not recommended for new disigns; sent by NKE Multigraphic --- README.md | 1 + hooks/VWT.js | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ hooks/index.js | 1 + test/VWT.js | 26 +++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 hooks/VWT.js create mode 100644 test/VWT.js diff --git a/README.md b/README.md index 05f4c38a..3c802cad 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ - [VPW - Speed - Measured Parallel to Wind](https://gpsd.gitlab.io/gpsd/NMEA.html#_vpw_speed_measured_parallel_to_wind) - [VTG - Track Made Good and Ground Speed](https://gpsd.gitlab.io/gpsd/NMEA.html#_vtg_track_made_good_and_ground_speed) - [VWR - Relative Wind Speed and Angle](https://gpsd.gitlab.io/gpsd/NMEA.html#_vwr_relative_wind_speed_and_angle) +- [VWT - True Wind Angle and Speed](https://lists.nongnu.org/archive/html/gpsd-dev/2012-04/msg00048.html) - [ZDA - UTC day, month, and year, and local time zone offset](https://gpsd.gitlab.io/gpsd/NMEA.html#_zda_time_amp_date_utc_day_month_year_and_local_time_zone) - [XTE - Cross-track Error](https://www.tronico.fi/OH6NT/docs/NMEA0183.pdf) - [ZDA - UTC day, month, and year, and local time zone offset](http://www.trimble.com/oem_receiverhelp/v4.44/en/NMEA-0183messages_ZDA.html) diff --git a/hooks/VWT.js b/hooks/VWT.js new file mode 100644 index 00000000..22a11838 --- /dev/null +++ b/hooks/VWT.js @@ -0,0 +1,102 @@ +'use strict' + +/** + * Copyright 2016 Signal K and Fabian Tollenaar . + * + * 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 debug = require('debug')('signalk-parser-nmea0183/VWT') +const utils = require('@signalk/nmea0183-utilities') + +/* + * $WIVWT,<0>,<1>,<2>,<3>,<4>,<5>,<6>,<7>*hh + * + * NMEA 0183 True wind angle in relation to the vessel's heading, and true wind + * speed referenced to the water. True wind is the vector sum of the Relative + * (apparent) wind vector and the vessel's velocity vector relative to the water along + * the heading line of the vessel. It represents the wind at the vessel if it were + * stationary relative to the water and heading in the same direction. + * + * <0> Calculated wind angle relative to the vessel, 0 to 180°, left/right of + * vessel heading, to the nearest 0.1 degree + * <1> L = left, or R = right + * <2> Calculated wind speed, knots, to the nearest 0.1 knot + * <3> N = knots + * <4> Wind speed, meters per second, to the nearest 0.1 m/s + * <5> M = meters per second + * <6> Wind speed, km/h, to the nearest km/h + * <7> K = km/h + */ + +// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 + + +function convertToWindAngle(angle) { + const numAngle = utils.float(angle) % 360 + if (numAngle > 180 && numAngle <= 360) { + return numAngle - 360 + } + return numAngle +} + +module.exports = function(input) { + const { id, sentence, parts, tags } = input; + + if(!parts[0]) { + return null; + } + var angle = convertToWindAngle(parts[0]); + + + if(!parts[1]) { + return null; + } + switch( parts[1].toUpperCase() ) { + case 'L': + angle = -1 * utils.transform( angle, 'deg', 'rad'); + break; + case 'R': + angle = utils.transform( angle, 'deg', 'rad'); + break; + default: + return null; + } + + + if(!parts[2] || parts[3].toUpperCase() !== "N") { + return null; + } + const speed = utils.transform(parts[2], 'knots', 'ms') + + const delta = { + updates: [ + { + source: tags.source, + timestamp: tags.timestamp, + values: [ + { + path: 'environment.wind.speedTrue', + value: speed + }, + { + path: 'environment.wind.angleTrueWater', + value: angle + } + ] + } + ], + } + + return delta +} diff --git a/hooks/index.js b/hooks/index.js index f51e8e2c..5083c5cb 100644 --- a/hooks/index.js +++ b/hooks/index.js @@ -31,6 +31,7 @@ module.exports = { 'VPW': require('./VPW.js'), 'VTG': require('./VTG.js'), 'VWR': require('./VWR.js'), + 'VWT': require('./VWT.js'), 'ZDA': require('./ZDA.js'), 'XTE': require('./XTE.js'), 'BOD': require('./BOD.js'), diff --git a/test/VWT.js b/test/VWT.js new file mode 100644 index 00000000..f2fd9c13 --- /dev/null +++ b/test/VWT.js @@ -0,0 +1,26 @@ +'use strict' + +const Parser = require('../lib') +const chai = require('chai') +const should = chai.Should() + +chai.use(require('chai-things')) + +describe('VWT', () => { + it('True wind converts ok', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75') +//'$IIMWV,074,T,05.85,N,A*2E' +// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 + + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) + + + it('Doesn\'t choke on empty sentences', () => { + const delta = new Parser().parse('$IIVWT,,,,*55') + should.equal(delta, null) + }) + + +}) From d077054b7858fd551848c0a48205734b2a6a6f4f Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Sun, 4 Oct 2020 09:32:18 +0200 Subject: [PATCH 05/11] cosmetics: removed whitespace --- hooks/VWT.js | 6 +++--- test/VWT.js | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hooks/VWT.js b/hooks/VWT.js index 22a11838..528927a6 100644 --- a/hooks/VWT.js +++ b/hooks/VWT.js @@ -39,7 +39,7 @@ const utils = require('@signalk/nmea0183-utilities') * <7> K = km/h */ -// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 +// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 function convertToWindAngle(angle) { @@ -57,7 +57,7 @@ module.exports = function(input) { return null; } var angle = convertToWindAngle(parts[0]); - + if(!parts[1]) { return null; @@ -97,6 +97,6 @@ module.exports = function(input) { } ], } - + return delta } diff --git a/test/VWT.js b/test/VWT.js index f2fd9c13..1b0d744a 100644 --- a/test/VWT.js +++ b/test/VWT.js @@ -10,8 +10,8 @@ describe('VWT', () => { it('True wind converts ok', () => { const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75') //'$IIMWV,074,T,05.85,N,A*2E' -// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 - +// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.angleTrueWater') delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) }) @@ -22,5 +22,4 @@ describe('VWT', () => { should.equal(delta, null) }) - }) From a369a4c4cbf10be258957e6ae7c2d6ab5f0e70d0 Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Sun, 4 Oct 2020 09:34:53 +0200 Subject: [PATCH 06/11] cosmetics: removed whitespace --- test/VWT.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/VWT.js b/test/VWT.js index 1b0d744a..916eed3f 100644 --- a/test/VWT.js +++ b/test/VWT.js @@ -11,7 +11,7 @@ describe('VWT', () => { const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75') //'$IIMWV,074,T,05.85,N,A*2E' // $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 - + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.angleTrueWater') delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) }) From 5a05ab6c77a5446a4d87dc28096b9a1ee3932967 Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Tue, 13 Oct 2020 11:37:17 +0200 Subject: [PATCH 07/11] check for unit 'C' in MTA sentence --- hooks/MTA.js | 6 ++++-- test/MTA.js | 16 +++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/hooks/MTA.js b/hooks/MTA.js index 9a118f64..b898efd6 100644 --- a/hooks/MTA.js +++ b/hooks/MTA.js @@ -33,8 +33,11 @@ */ module.exports = function (input) { - const { id, sentence, parts, tags } = input + const { id, sentence, parts, tags } = input; + if(parts[1] != 'C') { + return null; + } const delta = { updates: [ { @@ -44,7 +47,6 @@ module.exports = function (input) { { path: 'environment.outside.temperature', value: utils.transform(utils.float(parts[0]), 'c', 'k') - //returns raw value, no transformation done } ] } diff --git a/test/MTA.js b/test/MTA.js index 0fe24e01..64b48f22 100644 --- a/test/MTA.js +++ b/test/MTA.js @@ -23,10 +23,16 @@ chai.Should() chai.use(require('chai-things')) describe('MTA', () => { - it('Converts OK using individual parser', () => { - const delta = new Parser().parse('$IIMTA,26.,C*31') + it('Converts OK using individual parser', () => { + const delta = new Parser().parse('$IIMTA,26.,C*31') - delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.outside.temperature') - delta.updates[0].values[0].value.should.be.closeTo(299.15, 0.005) - }) + delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.outside.temperature') + delta.updates[0].values[0].value.should.be.closeTo(299.15, 0.005) + }) + it('Does not accept units other than Celsius', () => { + var should = chai.should(); + const delta = new Parser().parse('$IIMTA,26.,F*34') + + should.equal(delta,null); + }) }) From fbb7244d1c1eff608789021e7b4a0454b6ba3bca Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Tue, 13 Oct 2020 13:45:33 +0200 Subject: [PATCH 08/11] - checks for correct values (T,M,K,M) in designator and unit fields in MWD sentence - returns true/magnetic direction whichever is present - returns speed given in m/s if both kn and m/s are present - tests for correct pathes by position --- hooks/MWD.js | 78 +++++++++++++++++++++++++++---------------- test/MWD.js | 93 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 136 insertions(+), 35 deletions(-) diff --git a/hooks/MWD.js b/hooks/MWD.js index b3b9f440..7538b9be 100644 --- a/hooks/MWD.js +++ b/hooks/MWD.js @@ -35,37 +35,59 @@ const utils = require('@signalk/nmea0183-utilities') */ module.exports = function(input) { - const { id, sentence, parts, tags } = input - var pathValues = [] + const { id, sentence, parts, tags } = input; + var pathValues = []; - if(parts[0] != ''){ + // get direction data: + // return both, true and magnetic direction, if present in the NMEA sentence + var haveDirection = false; + if(parts[0] != '' && parts[1] == 'T') { + haveDirection = true; + pathValues.push({ + 'path': 'environment.wind.directionTrue', + 'value': utils.transform(utils.float(parts[0]), 'deg', 'rad') + }) + } + if(parts[2] != '' && parts[3] == 'M') { + haveDirection = true; + pathValues.push({ + 'path': 'environment.wind.directionMagnetic', + 'value': utils.transform(utils.float(parts[2]), 'deg', 'rad') + }) + } + if( !haveDirection ) { + return null; + } + + // get speed data: + // speed given in kn is used in case no speed in m/s is present in the NMEA sentence + var haveSpeed = false; + var speed; + if(parts[4] != '' && parts[5] == 'N') { + haveSpeed = true; + speed = utils.transform(utils.float(parts[4]), 'knots', 'ms'); + } + if(parts[6] != '' && parts[7] == 'M') { + haveSpeed = true; + speed = utils.float(parts[6]); + } + if( !haveSpeed ) { + return null; + } pathValues.push({ - 'path': 'environment.wind.directionTrue', - 'value': utils.transform(utils.float(parts[0]), 'deg', 'rad') + 'path': 'environment.wind.speedTrue', + 'value': speed }) - } - if(parts[2] != ''){ - pathValues.push({ - 'path': 'environment.wind.directionMagnetic', - 'value': utils.transform(utils.float(parts[2]), 'deg', 'rad') - }) - } - if(parts[4] != ''){ - pathValues.push({ - 'path': 'environment.wind.speedTrue', - 'value': utils.transform(utils.float(parts[4]), 'knots', 'ms') - }) - } - const delta = { - updates: [ - { - source: tags.source, - timestamp: tags.timestamp, - values: pathValues - } - ], - } + const delta = { + updates: [ + { + source: tags.source, + timestamp: tags.timestamp, + values: pathValues + } + ], + } - return delta + return delta } diff --git a/test/MWD.js b/test/MWD.js index d56184e5..64c4492a 100644 --- a/test/MWD.js +++ b/test/MWD.js @@ -24,13 +24,92 @@ chai.use(require('chai-things')) describe('MWD', () => { - it('speed & direction data', () => { - const delta = new Parser().parse('$IIMWD,,,046.,M,10.1,N,05.2,M*0B') + it('speed & direction data (#1)', () => { + const delta = new Parser().parse('$IIMWD,,,046.,M,10.1,N,05.2,M*0B') - delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.speedTrue') - delta.updates[0].values[1].value.should.be.closeTo(5.19585, 0.00005) - delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.directionMagnetic') - delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) - }) + delta.updates[0].values[0].path.should.equal('environment.wind.directionMagnetic') + delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) + delta.updates[0].values[1].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[1].value.should.equal(5.2) + }) + it('speed & direction data (#2)', () => { + const delta = new Parser().parse('$IIMWD,046.,T,046.,M,10.1,N,,*17') + + delta.updates[0].values[0].path.should.equal('environment.wind.directionTrue') + delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) + delta.updates[0].values[1].path.should.equal('environment.wind.directionMagnetic') + delta.updates[0].values[1].value.should.be.closeTo(0.802851, 0.00005) + delta.updates[0].values[2].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[2].value.should.be.closeTo(5.2, 0.005) + }) + + it('speed & direction data (#3)', () => { + const delta = new Parser().parse('$IIMWD,046.,T,,,,,5.2,M*72') + + delta.updates[0].values[0].path.should.equal('environment.wind.directionTrue') + delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) + delta.updates[0].values[1].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[1].value.should.be.equal(5.2) + }) + + it('missing direction data', () => { + var should = chai.should() + const delta = new Parser().parse('$IIMWD,,,,,,,5.2,M*3A') + + should.equal(delta,null); + }) + + it('missing speed data', () => { + var should = chai.should() + const delta = new Parser().parse('$IIMWD,,,046.,M,,,,*0F') + + should.equal(delta,null); + }) + + it('improper direction designator (#1)', () => { + var should = chai.should() + const delta = new Parser().parse('$IIMWD,,,046.,T,,,,*16') + + should.equal(delta,null); + }) + + it('improper direction designator (#2)', () => { + var should = chai.should() + const delta = new Parser().parse('$IIMWD,046.,M,,,,,,*0F') + + should.equal(delta,null); + }) + + it('improper speed designator (#1)', () => { + var should = chai.should() + const delta = new Parser().parse('$IIMWD,,,046.,M,10.1,n,,*7F') + + should.equal(delta,null); + }) + + it('improper speed designator (#2)', () => { + var should = chai.should() + const delta = new Parser().parse('$IIMWD,,,046.,M,,,0.0,m*4C') + + should.equal(delta,null); + }) + + it('improper direction designator for degrees magnetic, using degrees true', () => { + const delta = new Parser().parse('$IIMWD,046.,T,0.,m,10.1,N,5.2,M*51') + + delta.updates[0].values[0].path.should.equal('environment.wind.directionTrue') + delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) + delta.updates[0].values[1].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[1].value.should.equal(5.2) + }) + + it('improper speed designator for m/s, using speed in kn', () => { + const delta = new Parser().parse('$IIMWD,,,046.,M,10.1,N,0.0,m*1C') + + delta.updates[0].values[0].path.should.equal('environment.wind.directionMagnetic') + delta.updates[0].values[0].value.should.be.closeTo(0.802851, 0.00005) + delta.updates[0].values[1].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[1].value.should.be.closeTo(5.2, 0.005) + }) }) From 8e5a1a80d8ffeeb9ae9f48b9b8a1bbc8316bda2b Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Tue, 13 Oct 2020 16:12:07 +0200 Subject: [PATCH 09/11] - checks for designator/unit fields in VWT sentence - returns value given in m/s if present, kn and km/h as fallback - tests for calculation of angles, missing data, improper designators --- hooks/VWT.js | 26 ++++++++--- test/VWT.js | 126 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 135 insertions(+), 17 deletions(-) diff --git a/hooks/VWT.js b/hooks/VWT.js index 528927a6..424f46a4 100644 --- a/hooks/VWT.js +++ b/hooks/VWT.js @@ -53,16 +53,16 @@ function convertToWindAngle(angle) { module.exports = function(input) { const { id, sentence, parts, tags } = input; + // get direction if(!parts[0]) { return null; } var angle = convertToWindAngle(parts[0]); - if(!parts[1]) { return null; } - switch( parts[1].toUpperCase() ) { + switch( parts[1] ) { case 'L': angle = -1 * utils.transform( angle, 'deg', 'rad'); break; @@ -73,12 +73,26 @@ module.exports = function(input) { return null; } - - if(!parts[2] || parts[3].toUpperCase() !== "N") { + // get speed data: + // speed value given in m/s is given precedence if present in the NMEA sentence + var haveSpeed = false; + var speed; + if(parts[2] != '' && parts[3] == 'N') { + haveSpeed = true; + speed = utils.transform(utils.float(parts[2]), 'knots', 'ms'); + } + if(parts[6] != '' && parts[7] == 'K') { + haveSpeed = true; + speed = utils.transform(utils.float(parts[6]), 'kph', 'ms'); + } + if(parts[4] != '' && parts[5] == 'M') { // overwrite speed from knots or km/h if present + haveSpeed = true; + speed = utils.float(parts[4]); + } + if( !haveSpeed ) { return null; } - const speed = utils.transform(parts[2], 'knots', 'ms') - + const delta = { updates: [ { diff --git a/test/VWT.js b/test/VWT.js index 916eed3f..d1779170 100644 --- a/test/VWT.js +++ b/test/VWT.js @@ -7,19 +7,123 @@ const should = chai.Should() chai.use(require('chai-things')) describe('VWT', () => { - it('True wind converts ok', () => { - const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75') -//'$IIMWV,074,T,05.85,N,A*2E' -// $IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75 + it('speed & direction data (#1)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,05.2,M,018.7,K*75') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) - delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.wind.angleTrueWater') - delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) - }) + it('speed & direction data (#2)', () => { + const delta = new Parser().parse('$IIVWT,180.,R,10.1,N,05.2,M,018.7,K*7F') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(3.1415, 0.005) + }) + it('speed & direction data (#3)', () => { // 190R = 170L + const delta = new Parser().parse('$IIVWT,190.,R,10.1,N,05.2,M,018.7,K*7E') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(-2.967, 0.005) + }) - it('Doesn\'t choke on empty sentences', () => { - const delta = new Parser().parse('$IIVWT,,,,*55') - should.equal(delta, null) - }) + it('speed & direction data (#4)', () => { + const delta = new Parser().parse('$IIVWT,170.,L,10.1,N,05.2,M,018.7,K*6E') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(-2.967, 0.005) + }) + + it('speed & direction data (#5)', () => { // 170 + 360 = 530 + const delta = new Parser().parse('$IIVWT,530.,L,10.1,N,05.2,M,018.7,K*6E') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(-2.967, 0.005) + }) + + it('missing speed data (#1)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,,N,05.2,M,018.7,*20') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) + + it('missing speed data (#2)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,,,018.7,K*21') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.be.closeTo(5.2, 0.05) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) + + it('missing speed data (#3)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,,,,K*01') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.be.closeTo(5.2, 0.05) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) + + it('missing direction data (#1)', () => { + const delta = new Parser().parse('$IIVWT,,R,10.1,N,,,,K*1C') + + should.equal(delta,null); + }) + + it('missing direction data (#2)', () => { + const delta = new Parser().parse('$IIVWT,0.0,,10.1,N,,,,K*60') + + should.equal(delta,null); + }) + + it('improper direction designator (#1)', () => { + const delta = new Parser().parse('$IIVWT,030.,r,10.1,N,05.2,M,018.7,K*55') + + should.equal(delta,null); + }) + + it('improper speed designator (#1)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,X,05.2,M,018.7,X*70') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.equal(5.2) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) + + it('improper speed designator (#2)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,N,05.2,X,018.7,K*60') + + delta.updates[0].values[0].path.should.equal('environment.wind.speedTrue') + delta.updates[0].values[0].value.should.be.closeTo(5.2, 0.05) + delta.updates[0].values[1].path.should.equal('environment.wind.angleTrueWater') + delta.updates[0].values[1].value.should.be.closeTo(0.523599, 0.005) + }) + + it('improper speed designator (#3)', () => { + const delta = new Parser().parse('$IIVWT,030.,R,10.1,X,05.2,X,018.7,X*65') + + should.equal(delta,null); + }) + + it('Doesn\'t choke on empty sentences', () => { + const delta = new Parser().parse('$IIVWT,,,,*55') + should.equal(delta, null) + }) }) From 3cd6751a16d530bfded29f8b733b7d7fbb0719a8 Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Tue, 13 Oct 2020 17:23:20 +0200 Subject: [PATCH 10/11] test of path by position --- test/MTA.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/MTA.js b/test/MTA.js index 64b48f22..5902909b 100644 --- a/test/MTA.js +++ b/test/MTA.js @@ -18,15 +18,15 @@ const Parser = require('../lib') const chai = require('chai') +const should = chai.Should() -chai.Should() chai.use(require('chai-things')) describe('MTA', () => { it('Converts OK using individual parser', () => { const delta = new Parser().parse('$IIMTA,26.,C*31') - delta.updates[0].values.should.contain.an.item.with.property('path', 'environment.outside.temperature') + delta.updates[0].values[0].path.should.equal('environment.outside.temperature') delta.updates[0].values[0].value.should.be.closeTo(299.15, 0.005) }) it('Does not accept units other than Celsius', () => { From b48fbee8f9a398e8ec845b212cac20254d58413e Mon Sep 17 00:00:00 2001 From: Hans-Peter Bergander Date: Tue, 13 Oct 2020 17:27:29 +0200 Subject: [PATCH 11/11] cleanups --- test/MWD.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/MWD.js b/test/MWD.js index 64c4492a..d180326b 100644 --- a/test/MWD.js +++ b/test/MWD.js @@ -54,42 +54,36 @@ describe('MWD', () => { }) it('missing direction data', () => { - var should = chai.should() const delta = new Parser().parse('$IIMWD,,,,,,,5.2,M*3A') should.equal(delta,null); }) it('missing speed data', () => { - var should = chai.should() const delta = new Parser().parse('$IIMWD,,,046.,M,,,,*0F') should.equal(delta,null); }) it('improper direction designator (#1)', () => { - var should = chai.should() const delta = new Parser().parse('$IIMWD,,,046.,T,,,,*16') should.equal(delta,null); }) it('improper direction designator (#2)', () => { - var should = chai.should() const delta = new Parser().parse('$IIMWD,046.,M,,,,,,*0F') should.equal(delta,null); }) it('improper speed designator (#1)', () => { - var should = chai.should() const delta = new Parser().parse('$IIMWD,,,046.,M,10.1,n,,*7F') should.equal(delta,null); }) it('improper speed designator (#2)', () => { - var should = chai.should() const delta = new Parser().parse('$IIMWD,,,046.,M,,,0.0,m*4C') should.equal(delta,null);