From 47a0f56d0d92a22338af00c833c9b1ec456747ca Mon Sep 17 00:00:00 2001 From: Nathan Kellenicki Date: Fri, 18 Jan 2019 14:46:31 -0800 Subject: [PATCH] Now fetches firmware revisions for WeDo 2.0 Smart Hubs --- src/consts.ts | 1 + src/hub.ts | 22 ++++++++++++++++++--- src/lpf2hub.ts | 46 ++++++++++++++++++++++++-------------------- src/wedo2smarthub.ts | 18 +++++++++++++++++ tslint.json | 2 +- 5 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/consts.ts b/src/consts.ts index 1124e4f..02860e0 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -137,6 +137,7 @@ export enum BLEService { export enum BLECharacteristic { WEDO2_BATTERY = "2a19", + WEDO2_FIRMWARE_REVISION = "2a26", WEDO2_BUTTON = "00001526-1212-efde-1523-785feabcd123", // "1526" WEDO2_PORT_TYPE = "00001527-1212-efde-1523-785feabcd123", // "1527" // Handles plugging and unplugging of devices on WeDo 2.0 Smart Hub WEDO2_LOW_VOLTAGE_ALERT = "00001528-1212-efde-1523-785feabcd123", // "1528" diff --git a/src/hub.ts b/src/hub.ts index 0b61f8d..2b6a147 100644 --- a/src/hub.ts +++ b/src/hub.ts @@ -9,6 +9,14 @@ import Debug = require("debug"); const debug = Debug("hub"); +export interface IFirmwareInfo { + major: number; + minor: number; + bugFix: number; + build: number; +} + + /** * @class Hub * @ignore @@ -25,7 +33,7 @@ export class Hub extends EventEmitter { protected _characteristics: {[uuid: string]: Characteristic} = {}; protected _name: string; - protected _firmwareVersion: string = "0.0.0.0"; + protected _firmwareInfo: IFirmwareInfo = { major: 0, minor: 0, bugFix: 0, build: 0 }; protected _batteryLevel: number = 100; private _peripheral: Peripheral; @@ -55,7 +63,7 @@ export class Hub extends EventEmitter { * @property {string} firmwareVersion Firmware version of the hub */ public get firmwareVersion () { - return this._firmwareVersion; + return `${this._firmwareInfo.major}.${this._firmwareInfo.minor}.${this._lpad(this._firmwareInfo.bugFix.toString(), 2)}.${this._lpad(this._firmwareInfo.build.toString(), 4)}`; } @@ -366,7 +374,7 @@ export class Hub extends EventEmitter { }, delay); port.setEventTimer(interval); return emitter; -} + } protected _portLookup (port: string) { @@ -377,6 +385,14 @@ export class Hub extends EventEmitter { } + protected _lpad (str: string, length: number) { + while (str.length < length) { + str = "0" + str; + } + return str; + } + + private _getModeForDeviceType (type: Consts.DeviceType) { switch (type) { case Consts.DeviceType.BASIC_MOTOR: diff --git a/src/lpf2hub.ts b/src/lpf2hub.ts index 2423d07..b40e5d2 100644 --- a/src/lpf2hub.ts +++ b/src/lpf2hub.ts @@ -6,6 +6,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); +import { promises } from "fs"; const debug = Debug("lpf2hub"); @@ -39,14 +40,16 @@ export class LPF2Hub extends Hub { await super.connect(); const characteristic = this._getCharacteristic(Consts.BLECharacteristic.LPF2_ALL); this._subscribeToCharacteristic(characteristic, this._parseMessage.bind(this)); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x02, 0x02])); // Activate button reports - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x03, 0x05])); // Get firmware version - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x06, 0x02])); // Get battery level? - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate current reports - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate voltage reports - if (this.type === Consts.HubType.DUPLO_TRAIN_HUB) { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01])); - } + setTimeout(() => { + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x03, 0x05])); // Request firmware version + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x02, 0x02])); // Activate button reports + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x06, 0x02])); // Activate battery level reports + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate current reports + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate voltage reports + if (this.type === Consts.HubType.DUPLO_TRAIN_HUB) { + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01])); + } + }, 1000); return resolve(); }); } @@ -113,6 +116,15 @@ export class LPF2Hub extends Hub { } + public sendRaw (message: Buffer) { + return new Promise((resolve, reject) => { + this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, message, () => { + return resolve(); + }); + }); + } + + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), callback); } @@ -178,8 +190,6 @@ export class LPF2Hub extends Hub { private _parseDeviceInfo (data: Buffer) { - console.log(data); - if (data[3] === 2) { if (data[5] === 1) { /** @@ -195,17 +205,11 @@ export class LPF2Hub extends Hub { return; } } else if (data[3] === 3) { - const fwData = data.slice(5, data.length); - let bcd = fwData.readUInt8(3); - const major = bcd >>> 4; - const minor = bcd & 0xf; - bcd = fwData.readUInt8(2); - const bugFix = bcd >>> 4 * 10 + bcd & 0xf; - bcd = fwData.readUInt8(1); - let build = bcd >>> 4 * 1000 + bcd & 0xf * 100; - bcd = fwData.readUInt8(0); - build = build + bcd >>> 4 * 10 + bcd & 0xf; - this._firmwareVersion = `${major}.${minor}.${bugFix}.${build}`; + const build = data.readUInt16LE(5); + const bugFix = data.readUInt8(7); + const major = data.readUInt8(8) >>> 4; + const minor = data.readUInt8(8) & 0xf; + this._firmwareInfo = { major, minor, bugFix, build }; } } diff --git a/src/wedo2smarthub.ts b/src/wedo2smarthub.ts index 2fe304a..0d5dc66 100644 --- a/src/wedo2smarthub.ts +++ b/src/wedo2smarthub.ts @@ -57,6 +57,9 @@ export class WeDo2SmartHub extends Hub { this._getCharacteristic(Consts.BLECharacteristic.WEDO2_BATTERY).read((err, data) => { this._parseBatteryMessage(data); }); + this._getCharacteristic(Consts.BLECharacteristic.WEDO2_FIRMWARE_REVISION).read((err, data) => { + this._parseFirmwareRevisionString(data); + }); debug("Connect completed"); return resolve(); }); @@ -237,6 +240,15 @@ export class WeDo2SmartHub extends Hub { } + public sendRaw (message: Buffer, characteristic: string = Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE) { + return new Promise((resolve, reject) => { + this._writeMessage(characteristic, message, () => { + return resolve(); + }); + }); + } + + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { this._writeMessage(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), callback); } @@ -265,6 +277,12 @@ export class WeDo2SmartHub extends Hub { } + private _parseFirmwareRevisionString (data: Buffer) { + const parts = data.toString().split("."); + this._firmwareInfo = { major: parseInt(parts[0], 10), minor: parseInt(parts[1], 10), bugFix: parseInt(parts[2], 10), build: parseInt(parts[3], 10) }; + } + + private _parsePortMessage (data: Buffer) { const port = this._getPortForPortNumber(data[0]); diff --git a/tslint.json b/tslint.json index f0d91cd..c727815 100644 --- a/tslint.json +++ b/tslint.json @@ -14,7 +14,7 @@ "typedef": true, "no-console": false, "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"], - "object-literal-key-quotes": "consistent", + "object-literal-key-quotes": false, "object-literal-sort-keys": false, "no-string-literal": false, "no-shadowed-variable": [false]