diff --git a/Dockerfile b/Dockerfile index 6cf89ba..ddb5a4b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,8 @@ RUN mkdir /app WORKDIR /app COPY ["package.json", "/app/"] -RUN npm install +COPY ["package-lock.json", "/app/"] +RUN npm install --no-fund COPY ["src", "/app/src"] diff --git a/src/index.js b/src/index.js index f05dc28..d6776ef 100644 --- a/src/index.js +++ b/src/index.js @@ -41,7 +41,7 @@ let loop; console.log(v.toString()); } - const mqttHA = new MQTT('homeassistant', vehicles[0].vin); + const mqttHA = new MQTT(vehicles[0], 'homeassistant'); const availTopic = mqttHA.getAvailabilityTopic(); const client = await mqtt.connectAsync(`${mqttConfig.tls ? 'mqtts' : 'mqtt'}://${mqttConfig.host}:${mqttConfig.port}`, { @@ -55,34 +55,33 @@ let loop; const configurations = new Map(); const run = async () => { const states = new Map(); - // Note: the library is set to use only the configured VIN, but using multiple for future proofing. - for (const v of vehicles) { - console.log('Requesting diagnostics:') - const statsRes = await onStar.diagnostics({ - diagnosticItem: v.getSupported() - }); - console.log(_.get(statsRes, 'status')); - const stats = _.map( - _.get(statsRes, 'response.data.commandResponse.body.diagnosticResponse'), - d => new Diagnostic(d) - ); + const v = vehicles[0]; + console.log('Requesting diagnostics:') + const statsRes = await onStar.diagnostics({ + diagnosticItem: v.getSupported() + }); + console.log(_.get(statsRes, 'status')); + const stats = _.map( + _.get(statsRes, 'response.data.commandResponse.body.diagnosticResponse'), + d => new Diagnostic(d) + ); - for (const s of stats) { - if (!s.hasElements()) { - continue; - } - // configure once, then set or update states - for (const d of s.diagnosticElements) { - const topic = mqttHA.getConfigTopic(d) - const payload = mqttHA.getConfigPayload(s, d); - configurations.set(topic, {configured: false, payload}); - } - - const topic = mqttHA.getStateTopic(s); - const payload = mqttHA.getStatePayload(s); - states.set(topic, payload); + for (const s of stats) { + if (!s.hasElements()) { + continue; } + // configure once, then set or update states + for (const d of s.diagnosticElements) { + const topic = mqttHA.getConfigTopic(d) + const payload = mqttHA.getConfigPayload(s, d); + configurations.set(topic, {configured: false, payload}); + } + + const topic = mqttHA.getStateTopic(s); + const payload = mqttHA.getStatePayload(s); + states.set(topic, payload); } + // publish configs for (let [topic, config] of configurations) { // configure once if (!config.configured) { diff --git a/src/mqtt.js b/src/mqtt.js index 8867ff9..720651a 100644 --- a/src/mqtt.js +++ b/src/mqtt.js @@ -36,9 +36,10 @@ const _ = require('lodash'); * } */ class MQTT { - constructor(prefix = 'homeassistant', instance = 'XXX') { + constructor(vehicle, prefix = 'homeassistant') { this.prefix = prefix; - this.instance = instance; + this.vehicle = vehicle; + this.instance = vehicle.vin; } static convertName(name) { @@ -139,6 +140,12 @@ class MQTT { return { device_class, name, + device: { + identifiers: [this.vehicle.vin], + manufacturer: this.vehicle.make, + model: this.vehicle.year, + name: this.vehicle.toString() + }, availability_topic: this.getAvailabilityTopic(), payload_available: 'true', payload_not_available: 'false', diff --git a/src/vehicle.js b/src/vehicle.js index ebd7490..23f8b7d 100644 --- a/src/vehicle.js +++ b/src/vehicle.js @@ -27,7 +27,7 @@ class Vehicle { } toString() { - return `${this.year} ${this.make} ${this.model} ${this.vin}`; + return `${this.year} ${this.make} ${this.model}`; } } diff --git a/test/mqtt.spec.js b/test/mqtt.spec.js index f3ae6ae..19e616d 100644 --- a/test/mqtt.spec.js +++ b/test/mqtt.spec.js @@ -3,11 +3,13 @@ const _ = require('lodash'); const { Diagnostic } = require('../src/diagnostic'); const MQTT = require('../src/mqtt'); +const Vehicle = require('../src/vehicle'); const apiResponse = require('./diagnostic.sample.json'); describe('MQTT', () => { let mqtt; - beforeEach(() => mqtt = new MQTT()); + let vehicle = new Vehicle({make: 'foo', model: 'bar', vin: 'XXX', year: 2020}); + beforeEach(() => mqtt = new MQTT(vehicle)); it('should set defaults', () => { assert.strictEqual(mqtt.prefix, 'homeassistant'); @@ -57,6 +59,14 @@ describe('MQTT', () => { it('should generate config payloads', () => { assert.deepStrictEqual(mqtt.getConfigPayload(d, d.diagnosticElements[0]), { 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', @@ -79,6 +89,14 @@ describe('MQTT', () => { it('should generate config payloads', () => { 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: undefined, json_attributes_template: undefined, name: 'Priority Charge Indicator', @@ -103,6 +121,14 @@ describe('MQTT', () => { it('should generate payloads with an attribute', () => { assert.deepStrictEqual(mqtt.getConfigPayload(d, d.diagnosticElements[0]), { availability_topic: 'homeassistant/XXX/available', + device: { + identifiers: [ + 'XXX' + ], + manufacturer: 'foo', + model: 2020, + name: '2020 foo bar' + }, device_class: 'pressure', json_attributes_template: "{{ {'recommendation': value_json.tire_pressure_placard_front} | tojson }}", name: 'Tire Pressure: Left Front', diff --git a/test/vehicle.spec.js b/test/vehicle.spec.js index 9c66839..bb8facd 100644 --- a/test/vehicle.spec.js +++ b/test/vehicle.spec.js @@ -36,6 +36,6 @@ describe('Vehicle', () => { }); it('should toString() correctly', () => { - assert.strictEqual(v.toString(), '2020 Chevrolet Bolt EV foobarVIN') + assert.strictEqual(v.toString(), '2020 Chevrolet Bolt EV') }); });