Support conversions to imperial.
This commit is contained in:
parent
8c9747d711
commit
bd331a477c
@ -10,6 +10,9 @@ class Diagnostic {
|
|||||||
d => _.has(d, 'value') && _.has(d, 'unit')
|
d => _.has(d, 'value') && _.has(d, 'unit')
|
||||||
);
|
);
|
||||||
this.diagnosticElements = _.map(validEle, e => new DiagnosticElement(e));
|
this.diagnosticElements = _.map(validEle, e => new DiagnosticElement(e));
|
||||||
|
const converted = _.map(_.filter(this.diagnosticElements, e => e.isConvertible),
|
||||||
|
e => DiagnosticElement.convert(e));
|
||||||
|
this.diagnosticElements.push(... converted);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasElements() {
|
hasElements() {
|
||||||
@ -24,6 +27,29 @@ class Diagnostic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DiagnosticElement {
|
class DiagnosticElement {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {DiagnosticElement} element
|
||||||
|
*/
|
||||||
|
static convert(element) {
|
||||||
|
const {name, unit, value} = element;
|
||||||
|
const convertedUnit = Measurement.convertUnit(unit);
|
||||||
|
return new DiagnosticElement({
|
||||||
|
name: DiagnosticElement.convertName(name, convertedUnit),
|
||||||
|
unit: convertedUnit,
|
||||||
|
value: Measurement.convertValue(value, unit)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static convertName(name, unit) {
|
||||||
|
return `${name} ${_.replace(_.toUpper(unit), /\W/g, '')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} ele.name
|
||||||
|
* @param {string|number} ele.value
|
||||||
|
* @param {string} ele.unit
|
||||||
|
*/
|
||||||
constructor(ele) {
|
constructor(ele) {
|
||||||
this._name = ele.name;
|
this._name = ele.name;
|
||||||
this.measurement = new Measurement(ele.value, ele.unit);
|
this.measurement = new Measurement(ele.value, ele.unit);
|
||||||
@ -41,6 +67,10 @@ class DiagnosticElement {
|
|||||||
return this.measurement.unit;
|
return this.measurement.unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isConvertible() {
|
||||||
|
return this.measurement.isConvertible;
|
||||||
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return `${this.name}: ${this.measurement.toString()}`;
|
return `${this.name}: ${this.measurement.toString()}`;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ const _ = require('lodash');
|
|||||||
const Vehicle = require('./vehicle');
|
const Vehicle = require('./vehicle');
|
||||||
const {Diagnostic} = require('./diagnostic');
|
const {Diagnostic} = require('./diagnostic');
|
||||||
const MQTT = require('./mqtt');
|
const MQTT = require('./mqtt');
|
||||||
const {Commands} = require('./commands');
|
const Commands = require('./commands');
|
||||||
const logger = require('./logger');
|
const logger = require('./logger');
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
// const convert = require('convert-units');
|
const _ = require('lodash');
|
||||||
|
const convert = require('convert-units');
|
||||||
|
|
||||||
class Measurement {
|
class Measurement {
|
||||||
|
static CONVERTABLE_UNITS = [
|
||||||
|
'°C',
|
||||||
|
'km',
|
||||||
|
'kPa',
|
||||||
|
'km/l(e)'
|
||||||
|
];
|
||||||
|
|
||||||
constructor(value, unit) {
|
constructor(value, unit) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.unit = Measurement.correctUnitName(unit);
|
this.unit = Measurement.correctUnitName(unit);
|
||||||
|
this.isConvertible = _.includes(Measurement.CONVERTABLE_UNITS, this.unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +31,7 @@ class Measurement {
|
|||||||
case 'KPa':
|
case 'KPa':
|
||||||
return 'kPa';
|
return 'kPa';
|
||||||
case 'kmple':
|
case 'kmple':
|
||||||
return 'km/l(e)'; // TODO check on this
|
return 'km/l(e)';
|
||||||
case 'volts':
|
case 'volts':
|
||||||
case 'Volts':
|
case 'Volts':
|
||||||
return 'V';
|
return 'V';
|
||||||
@ -36,16 +45,50 @@ class Measurement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this may not be required. Check consuming application.
|
/**
|
||||||
/*static convertToImperial(value, unit) {
|
*
|
||||||
switch(unit) {
|
* @param {string|number} value
|
||||||
case 'Cel':
|
* @param {string} unit
|
||||||
const val = convert(value).from('C').to('F');
|
* @returns {string|number}
|
||||||
return new Measurement(val, 'F');
|
*/
|
||||||
default:
|
static convertValue(value, unit) {
|
||||||
return new Measurement(value, unit);
|
switch (unit) {
|
||||||
|
case '°C':
|
||||||
|
value = convert(value).from('C').to('F');
|
||||||
|
break;
|
||||||
|
case 'km':
|
||||||
|
value = convert(value).from('km').to('mi');
|
||||||
|
break;
|
||||||
|
case 'kPa':
|
||||||
|
value = convert(value).from('kPa').to('psi');
|
||||||
|
break;
|
||||||
|
case 'km/l(e)':
|
||||||
|
// km/L = (1.609344 / 3.785411784) * MPG
|
||||||
|
value = value / (1.609344 / 3.785411784);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}*/
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} unit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static convertUnit(unit) {
|
||||||
|
switch (unit) {
|
||||||
|
case '°C':
|
||||||
|
return '°F';
|
||||||
|
case 'km':
|
||||||
|
return 'mi';
|
||||||
|
case 'kPa':
|
||||||
|
return 'psi';
|
||||||
|
case 'km/l(e)':
|
||||||
|
return 'mpg(e)';
|
||||||
|
default:
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return `${this.value}${this.unit}`;
|
return `${this.value}${this.unit}`;
|
||||||
|
@ -191,17 +191,26 @@ class MQTT {
|
|||||||
return this.mapSensorConfigPayload(diag, diagEl, 'voltage');
|
return this.mapSensorConfigPayload(diag, diagEl, 'voltage');
|
||||||
case 'HYBRID BATTERY MINIMUM TEMPERATURE':
|
case 'HYBRID BATTERY MINIMUM TEMPERATURE':
|
||||||
case 'AMBIENT AIR TEMPERATURE':
|
case 'AMBIENT AIR TEMPERATURE':
|
||||||
|
case 'AMBIENT AIR TEMPERATURE F':
|
||||||
return this.mapSensorConfigPayload(diag, diagEl, 'temperature');
|
return this.mapSensorConfigPayload(diag, diagEl, 'temperature');
|
||||||
case 'EV BATTERY LEVEL':
|
case 'EV BATTERY LEVEL':
|
||||||
return this.mapSensorConfigPayload(diag, diagEl, 'battery');
|
return this.mapSensorConfigPayload(diag, diagEl, 'battery');
|
||||||
case 'TIRE PRESSURE LF':
|
case 'TIRE PRESSURE LF':
|
||||||
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Left Front', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_FRONT')}} | tojson }}`);
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Left Front', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_FRONT')}} | tojson }}`);
|
||||||
|
case 'TIRE PRESSURE LF PSI':
|
||||||
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Left Front PSI', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_FRONT')}} | tojson }}`);
|
||||||
case 'TIRE PRESSURE LR':
|
case 'TIRE PRESSURE LR':
|
||||||
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Left Rear', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_REAR')}} | tojson }}`);
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Left Rear', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_REAR')}} | tojson }}`);
|
||||||
|
case 'TIRE PRESSURE LR PSI':
|
||||||
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Left Rear PSI', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_REAR')}} | tojson }}`);
|
||||||
case 'TIRE PRESSURE RF':
|
case 'TIRE PRESSURE RF':
|
||||||
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Right Front', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_FRONT')}} | tojson }}`);
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Right Front', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_FRONT')}} | tojson }}`);
|
||||||
|
case 'TIRE PRESSURE RF PSI':
|
||||||
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Right Front PSI', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_FRONT')}} | tojson }}`);
|
||||||
case 'TIRE PRESSURE RR':
|
case 'TIRE PRESSURE RR':
|
||||||
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Right Rear', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_REAR')}} | tojson }}`);
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Right Rear', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_REAR')}} | tojson }}`);
|
||||||
|
case 'TIRE PRESSURE RR PSI':
|
||||||
|
return this.mapSensorConfigPayload(diag, diagEl, 'pressure', 'Tire Pressure: Right Rear PSI', `{{ {'recommendation': value_json.${MQTT.convertName('TIRE_PRESSURE_PLACARD_REAR')}} | tojson }}`);
|
||||||
// binary sensor
|
// binary sensor
|
||||||
case 'EV PLUG STATE': // unplugged/plugged
|
case 'EV PLUG STATE': // unplugged/plugged
|
||||||
return this.mapBinarySensorConfigPayload(diag, diagEl, 'plug');
|
return this.mapBinarySensorConfigPayload(diag, diagEl, 'plug');
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
const { Diagnostic } = require('../src/diagnostic');
|
const { Diagnostic, DiagnosticElement } = require('../src/diagnostic');
|
||||||
const apiResponse = require('./diagnostic.sample.json');
|
const apiResponse = require('./diagnostic.sample.json');
|
||||||
|
|
||||||
describe('Diagnostics', () => {
|
describe('Diagnostics', () => {
|
||||||
@ -12,13 +12,13 @@ describe('Diagnostics', () => {
|
|||||||
|
|
||||||
it('should parse a diagnostic response', () => {
|
it('should parse a diagnostic response', () => {
|
||||||
assert.strictEqual(d.name, 'AMBIENT AIR TEMPERATURE');
|
assert.strictEqual(d.name, 'AMBIENT AIR TEMPERATURE');
|
||||||
assert.strictEqual(d.diagnosticElements.length, 1);
|
assert.strictEqual(d.diagnosticElements.length, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toString() correctly', () => {
|
it('should toString() correctly', () => {
|
||||||
const output = d.toString().trimEnd();
|
const output = d.toString().trimEnd();
|
||||||
const lines = output.split(/\r\n|\r|\n/);
|
const lines = output.split(/\r\n|\r|\n/);
|
||||||
assert.strictEqual(lines.length, 2);
|
assert.strictEqual(lines.length, 3);
|
||||||
assert.strictEqual(lines[0], 'AMBIENT AIR TEMPERATURE:');
|
assert.strictEqual(lines[0], 'AMBIENT AIR TEMPERATURE:');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -28,15 +28,19 @@ describe('Diagnostics', () => {
|
|||||||
it('should parse a diagnostic element', () => {
|
it('should parse a diagnostic element', () => {
|
||||||
assert.strictEqual(d.name, 'TIRE PRESSURE');
|
assert.strictEqual(d.name, 'TIRE PRESSURE');
|
||||||
assert.ok(_.isArray(d.diagnosticElements));
|
assert.ok(_.isArray(d.diagnosticElements));
|
||||||
assert.strictEqual(d.diagnosticElements.length, 6);
|
assert.strictEqual(d.diagnosticElements.length, 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toString() correctly', () => {
|
it('should toString() correctly', () => {
|
||||||
const output = d.toString().trimEnd();
|
const output = d.toString().trimEnd();
|
||||||
const lines = output.split(/\r\n|\r|\n/);
|
const lines = output.split(/\r\n|\r|\n/);
|
||||||
assert.strictEqual(lines.length, 7);
|
assert.strictEqual(lines.length, 13);
|
||||||
assert.strictEqual(lines[0], 'TIRE PRESSURE:');
|
assert.strictEqual(lines[0], 'TIRE PRESSURE:');
|
||||||
assert.strictEqual(lines[1], ' TIRE PRESSURE LF: 240.0kPa');
|
assert.strictEqual(lines[1], ' TIRE PRESSURE LF: 240.0kPa');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should strip non-alpha chars', () => {
|
||||||
|
assert.strictEqual(DiagnosticElement.convertName('TEMP', '°F'), 'TEMP F');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -86,10 +86,31 @@ describe('MQTT', () => {
|
|||||||
unit_of_measurement: '°C',
|
unit_of_measurement: '°C',
|
||||||
value_template: '{{ value_json.ambient_air_temperature }}'
|
value_template: '{{ value_json.ambient_air_temperature }}'
|
||||||
});
|
});
|
||||||
|
assert.deepStrictEqual(mqtt.getConfigPayload(d, d.diagnosticElements[1]), {
|
||||||
|
availability_topic: 'homeassistant/XXX/available',
|
||||||
|
device: {
|
||||||
|
identifiers: [
|
||||||
|
'XXX'
|
||||||
|
],
|
||||||
|
manufacturer: 'foo',
|
||||||
|
model: 2020,
|
||||||
|
name: '2020 foo bar'
|
||||||
|
},
|
||||||
|
device_class: 'temperature',
|
||||||
|
json_attributes_template: undefined,
|
||||||
|
name: 'Ambient Air Temperature F',
|
||||||
|
payload_available: 'true',
|
||||||
|
payload_not_available: 'false',
|
||||||
|
state_topic: 'homeassistant/sensor/XXX/ambient_air_temperature/state',
|
||||||
|
json_attributes_topic: undefined,
|
||||||
|
unit_of_measurement: '°F',
|
||||||
|
value_template: '{{ value_json.ambient_air_temperature_f }}'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should generate state payloads', () => {
|
it('should generate state payloads', () => {
|
||||||
assert.deepStrictEqual(mqtt.getStatePayload(d), {
|
assert.deepStrictEqual(mqtt.getStatePayload(d), {
|
||||||
ambient_air_temperature: 15
|
ambient_air_temperature: 15,
|
||||||
|
ambient_air_temperature_f: 59
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user