Skip to content

Commit

Permalink
feature: PBVE - auxillary engine temperature (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonybentley authored and tkurki committed Aug 19, 2019
1 parent 4b3cdd7 commit 591c6e1
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 37 deletions.
209 changes: 179 additions & 30 deletions hooks/proprietary/PBVE.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@

const debug = require('debug')('signalk-parser-nmea0183/PBVE')
const utils = require('@signalk/nmea0183-utilities')
const alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
const schema = {

/*
OP30 digital oil pressure gauge sample NMEA sentence:
Note: oil pressure calculation formulas are the same for all instruments
OP30/OP60 digital oil pressure gauge sample NMEA sentence:
Sentence: $PBVE,DGOIADNNACAEACAAABBLAAEBAACMCFAAEPAIKI*37
Expand All @@ -34,85 +39,229 @@ $PBVE,x,x,xxxx,xxxx,xx,xx,xx,xx,xxxx,xxxx,xx,xxxx,xxxx,xx*xx
0: Product code: D = OP 30/60
1: Software version: G = ???
2: Oil pressure calibration number: OIAD = 14 8 0 3 = ???
3: A2D gain: NNAC = ???
2: Oil pressure calibration number: OIAD = 14 8 0 3 = 256*3 + 16*14 +8 = 1000 = 1.000
3: A2D gain: NNAC = 13 13 0 3 = 256*03 + 16*13 +13= 989= 0.989
4: Sender Type: AE = 4
5: Backlight level: AC = 2
6: Units of measure: AA = psi
6: Units of measure: AA = psi, otherwise bar
7: Built in alarms armed: AB = 1 = true
8: Low pressure alarm value: BLAA = 1 11 0 0 = ???
9: High pressure alarm value: EBAA = 4 1 0 0 = ???
8: Low pressure alarm value: BLAA = 1 11 0 0 = 256*0 + 16*1 +11= 27 psi
9: High pressure alarm value: EBAA = 4 1 0 0 = 256*0 + 16*4 +1= 65 psi
10: Checksum for Non-Volatile Memory: CM = 2 12 = ???
11: Oil Pressure: CFAA = 37
12: Sensor Volts: EPAI = 4 15 0 8 = ???
12: Sensor Volts: EPAI = 4 15 0 8 = 256*8 + 16*4 +15= 2116=2.116 VDC
13: Checksum: KI = 10 8
14: Checksum: 37
Where A=0, B=1, C=2, ... , O=14, P=15
Decode Oil Pressure as:
CFAA = 16*M + L + 4096*A + 256*A
CFAA = 16*C + F + 4096*A + 256*A
CFAA = 16*2 + 5 + 4096*0 + 256*0
CFAA = 37 psi
//ALPHA is an array map for converting sentence codes from letters to numbers
//alpha is an array map for converting sentence codes from letters to numbers
//A=0, B=1, etc
*/
D: {
path: 'propulsion.0.oilPressure',
meta: {
description: 'CruzPro OP30/OP60 Engine Oil Pressure Gauge',
units: 'pa',
displayName: 'Engine Oil Pressure',
shortName: 'EOP',
warnMethod: ['visual'],
alarmMethod: ['sound'],
gaugeAlarmOn: false,
backlight: 0,
zones: [],
originalValue: null,
}

},
/*
T30/T60 digital temperature gauge sample NMEA sentence:
Sentence: $PBVE,EDOIADOKACABABAAAACAPPCMABCGADABDOAEGL*20
Parse as:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
| | | | | | | | | | | | | | |
$PBVE,x,x,xxxx,xxxx,xx,xx,xx,xx,xxxx,xxxx,xx,xxxx,xxxx,xx*xx
$PBVE,E D OIAD OKAC AB AB AA AA CAPP CMAB CG ADAB DOAE GL 20
0: Product Code = E = T30/T60
1: Software Version #
2: Temperature Calibration Number
3: A2D gain
4: Sender Type
5: Backlight Level
6: Units of Measure (0= deg F, non-0= deg C)
7: Built-in Alarms Armed (AA=0 = NO)
8: Low temperature alarm value
9: High temperature alarm value
10: Checksum for Non-Volatile Memory
11: Engine Temperature
12: Sensor Volts
13: NMEA sentence checksum
14: Checksum
Where A=0, B=1, C=2, ... , O=14, P=15
Decode Temperature as:
ADAB = 16*A + D + 4096*A + 256*B
ADAB = 16*0 + 3 + 4096*0 +256*1
ADAB = 0 + 3 + 0 + 256
ADAB = 259 deg F
*/
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
E: {
path: 'propulsion.0.coolantTemperature',
meta: {
description: 'CruzPro T30/T60 Engine Coolant Temperature Gauge',
units: 'k',
displayName: 'Engine Coolant Temperature',
shortName: 'ECT',
warnMethod: ['visual'],
alarmMethod: ['sound'],
gaugeAlarmOn: false,
backlight: 0,
zones: [],
originalValue: null
}
}

}

/*
@function convertAlphasToInts
@param alphas String
@return Array
*/
function convertAlphasToInts(alphas){
function toInts(alphas){
let replacement = [];
let i;
alphas = alphas.split('')
var replacement = [];
for(var i = 0; i < alphas.length;i++){
const indexValue = ALPHA.indexOf(alphas[i]);
replacement.push(indexValue)

for(i = 0; i < alphas.length; i++){
replacement.push(alpha.indexOf(alphas[i]))
}
return replacement;
}


/*
@function convertToOilPressure
@param values Array
@function convertToValue
@param values String
@return Int
*/
function convertToOilPressure(values){
return (16 * values[0]) + values[1] + (4096 * values[2]) + (256 * values[3])
function convertToValue(values){
const parts = toInts(values)
return (16 * parts[0]) + parts[1] + (4096 * parts[2]) + (256 * parts[3])
}

module.exports = function(input) {
const { id, sentence, parts, tags } = input
/*
@function convertToAlarmValue
@param values String
@return Int
*/
function convertToAlarmValue(values){
const parts = toInts(values)
return ( (16 * parts[0]) + parts[1] + (256 * parts[2]) )
}

let values = []
module.exports = function(input) {
let convertedValue = {}
let delta = {}

const { id, sentence, parts, tags } = input
const data = parts[0]
const productCode = data.substr(0,1)

if(productCode !== 'D'){
debug('Unsupported CruzPro instrument type')
//just retun right away if not supported product code
if (productCode in schema === false) {
debug('Unsupported product code: ', productCode)
return;
}

const convertedValue = convertAlphasToInts(data.substr(28,4))
const oilPressure = convertToOilPressure(convertedValue)
const backlight = data.substr(8,2)
const gaugeUnits = data.substr(15,2)
const gaugeAlarmOn = data.substr(17,2)
const lower = convertToAlarmValue(data.substr(18,4))
const upper = convertToAlarmValue(data.substr(22,4))
const value = convertToValue(data.substr(28,4))

if (productCode === 'D') {

const conditionalValue = function(derivedValue){
return gaugeUnits === 'AA' ? derivedValue * 6894.757 : derivedValue * 100000
}

convertedValue = {
//convert to pascals from psi/bar
value: conditionalValue(value),
path: schema[productCode].path,
meta: schema[productCode].meta
}
convertedValue.meta.gaugeUnits = gaugeUnits === 'AA' ? 'psi' : 'bar'
//TODO: Add warning zone values
convertedValue.meta.zones = [
{
lower: conditionalValue(lower),
state: 'alarm',
message: 'Engine oil pressure at lowest threshold'
},
{
upper: conditionalValue(upper),
state: 'alarm',
message: 'Engine oil pressure at highest threshold'
}
]

} else if(productCode === 'E') {

const conditionalValue = function(derivedValue){
return (gaugeUnits === 'AA' ? (derivedValue - 32) * (5/9) + 273.15 : derivedValue + 273.15)
}

convertedValue = {
//convert to C from F
value: conditionalValue(value),
path: schema[productCode].path,
meta: schema[productCode].meta
}
convertedValue.meta.gaugeUnits = gaugeUnits === 'AA' ? 'f' : 'c'
//TODO: Add warning zone values
convertedValue.meta.zones = [
{
lower: conditionalValue(lower),
state: 'alarm',
message: 'Engine coolant temperature at lowest threshold'
},
{
upper: conditionalValue(upper),
state: 'alarm',
message: 'Engine coolant temperature at highest threshold'
}
]

const oilPressureValue = {
path: 'propulsion.0.oilPressure',
value: oilPressure
}

//baclight is AA, AB, etc so just need second value
convertedValue.meta.backlight = toInts(backlight)[1]
// instrument gauge alarm is armed when second value is 1 (A,B)
convertedValue.meta.gaugeAlarmOn = toInts(gaugeAlarmOn)[1] === 1
//store original value in meta
convertedValue.meta.originalValue = value;

delta = {
updates: [{
source: tags.source,
timestamp: tags.timestamp,
values: [oilPressureValue]
values: [convertedValue]
}]
}

Expand Down
74 changes: 69 additions & 5 deletions test/PBVE.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,78 @@ const should = require('chai').Should()
const toFull = require('./toFull')

describe('PBVE', () => {
it('Converts OK using individual parser', () => {

it('Converts engine oil pressure using individual parser', () => {
const delta = new Parser().parse('$PBVE,DGOIADNNACAEACAAABBLAAEBAACMCFAAEPAIKI*37')
delta.updates[0].values.should.contain.an.item.with.property('path', 'propulsion.0.oilPressure')
delta.updates[0].values[0].value.should.equal(37)
delta.updates[0].values[0].value.should.equal(255106.009)
delta.updates[0].values[0].meta.should.deep.equal(
{
description: 'CruzPro OP30/OP60 Engine Oil Pressure Gauge',
units: 'pa',
displayName: 'Engine Oil Pressure',
shortName: 'EOP',
warnMethod: [ 'visual' ],
alarmMethod: [ 'sound' ],
gaugeAlarmOn: true,
backlight: 2,
originalValue: 37,
gaugeUnits: 'psi',
zones: [
{
lower: 186158.43899999998,
state: 'alarm',
message: 'Engine oil pressure at lowest threshold'
},
{
upper: 448159.20499999996,
state: 'alarm',
message: 'Engine oil pressure at highest threshold'
}
]
}
)

toFull(delta).should.be.validSignalK
})
it('Converts engine coolant temperature using individual parser', () => {
const delta = new Parser().parse('$PBVE,EDOIADOKACABABAAAACAPPCMABCGADABDOAEGL*20')
delta.updates[0].values.should.contain.an.item.with.property('path', 'propulsion.0.coolantTemperature')
delta.updates[0].values[0].value.should.equal(399.26111111111106)
delta.updates[0].values[0].meta.should.deep.equal(
{
description: 'CruzPro T30/T60 Engine Coolant Temperature Gauge',
units: 'k',
displayName: 'Engine Coolant Temperature',
shortName: 'ECT',
warnMethod: ['visual'],
alarmMethod: ['sound'],
gaugeAlarmOn: false,
backlight: 2,
originalValue: 259,
gaugeUnits: 'f',
zones: [
{
lower: 2406.4833333333336,
state: 'alarm',
message: 'Engine coolant temperature at lowest threshold'
},
{
upper: 279.81666666666666,
state: 'alarm',
message: 'Engine coolant temperature at highest threshold'
}
]
}
)

toFull(delta).should.be.validSignalK
})
//currently only produce code D is supported so test that all others do not process
it('Will not convert if productCode not D', () => {
should.equal(new Parser().parse('$PBVE,FGLABCGJAAAHADEE*21'),undefined)

it('Should not parse if product code is F, B, or A', () => {
should.not.exist(new Parser().parse('$PBVE,FGLABCGJAAAHADEE*21'))
should.not.exist(new Parser().parse('$PBVE,BEAAADAAABFKBCIIBDAGOOABAAAAADAAAAOIACAAONFMAKCAADAAAAHG*2A'))
should.not.exist(new Parser().parse('$PBVE,AQHKAAAACIAAAAABAAGEDOBCAAAAFLABCKAADIAADIAAAAAANDEN*3F'))
})

})
4 changes: 2 additions & 2 deletions test/PNKEP.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
*/

const Parser = require('../lib')
const toFull = require("./toFull")
const chai = require("chai")
const should = chai.Should()
chai.use(require('@signalk/signalk-schema').chaiModule)
const toFull = require("./toFull")

chai.use(require('@signalk/signalk-schema').chaiModule)
chai.use(require("chai-things"))

describe("PNKEP", () => {
Expand Down

0 comments on commit 591c6e1

Please sign in to comment.