From d453fe52fbac8e7bc1e9b2a6de7ac7f5d7a5c340 Mon Sep 17 00:00:00 2001 From: Nathan Kellenicki Date: Fri, 6 Dec 2019 11:31:56 -0800 Subject: [PATCH] Basic implementation of BasicMotor types --- src/basicmotor.ts | 39 +++++ src/boostmovehub.ts | 24 +-- src/colordistancesensor.ts | 12 ++ src/consts.ts | 4 +- src/controlplushub.ts | 26 +-- src/controlpluslargemotor.ts | 12 ++ src/device.ts | 45 +++++ src/duplotrainbase.ts | 12 +- src/hub.ts | 83 +++++---- src/index-browser.ts | 24 ++- src/index-node.ts | 23 ++- src/interfaces.ts | 2 +- src/lpf2hub.ts | 159 ++++++++++-------- src/{nobledevice.ts => nobleabstraction.ts} | 4 +- src/poweredup-browser.ts | 6 +- src/poweredup-node.ts | 2 +- src/puphub.ts | 35 ++-- src/pupremote.ts | 4 +- src/simplemediumlinearmotor.ts | 12 ++ src/trainmotor.ts | 12 ++ src/{webbledevice.ts => webbleabstraction.ts} | 4 +- src/wedo2smarthub.ts | 99 ++++++----- 22 files changed, 437 insertions(+), 206 deletions(-) create mode 100644 src/basicmotor.ts create mode 100644 src/colordistancesensor.ts create mode 100644 src/controlpluslargemotor.ts create mode 100644 src/device.ts rename src/{nobledevice.ts => nobleabstraction.ts} (97%) create mode 100644 src/simplemediumlinearmotor.ts create mode 100644 src/trainmotor.ts rename src/{webbledevice.ts => webbleabstraction.ts} (97%) diff --git a/src/basicmotor.ts b/src/basicmotor.ts new file mode 100644 index 0000000..a9bd2cd --- /dev/null +++ b/src/basicmotor.ts @@ -0,0 +1,39 @@ +import { Device } from "./device"; +import { Hub } from "./hub"; + +import * as Consts from "./consts"; + +export class BasicMotor extends Device { + + + constructor (hub: Hub, portId: number, type: number = Consts.DeviceType.UNKNOWN) { + super(hub, portId, type); + } + + + /** + * Set the motor speed. + * @method BasicMotor#setSpeed + * @param {number} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. + * @returns {Promise} Resolved upon successful completion of command. + */ + public setSpeed (speed: number) { + return new Promise((resolve) => { + const data = Buffer.from([0x81, this.portId, 0x11, 0x51, 0x00, speed]); + this.send(data); + return resolve(); + }); + } + + + /** + * Fully (hard) stop the motor. + * @method BasicMotor#brake + * @returns {Promise} Resolved upon successful completion of command. + */ + public brake () { + return this.setSpeed(127); + } + + +} diff --git a/src/boostmovehub.ts b/src/boostmovehub.ts index 93c1222..784e0ed 100644 --- a/src/boostmovehub.ts +++ b/src/boostmovehub.ts @@ -7,7 +7,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("boostmovehub"); @@ -34,7 +34,7 @@ export class BoostMoveHub extends LPF2Hub { protected _currentPort = 0x3b; protected _voltagePort = 0x3c; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(device, autoSubscribe); this.type = Consts.HubType.BOOST_MOVE_HUB; this._ports = { @@ -102,17 +102,17 @@ export class BoostMoveHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } data.writeUInt16LE(time > 65535 ? 65535 : time, 4); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; } else { // @ts-ignore: The type of speed is properly checked at the start const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); // @ts-ignore: The type of time is properly checked at the start }, time); @@ -135,14 +135,14 @@ export class BoostMoveHub extends LPF2Hub { // @ts-ignore: The type of speed is properly checked at the start data = Buffer.from([0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; } else { // @ts-ignore: The type of speed is properly checked at the start const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); } } @@ -204,7 +204,7 @@ export class BoostMoveHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } data.writeUInt32LE(angle, 4); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; @@ -241,7 +241,7 @@ export class BoostMoveHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); data.writeInt32LE(pos, 4); } - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; @@ -265,7 +265,7 @@ export class BoostMoveHub extends LPF2Hub { } return new Promise((resolve) => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }); } @@ -295,11 +295,11 @@ export class BoostMoveHub extends LPF2Hub { portObj.cancelEventTimer(); return new Promise((resolve, reject) => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); if (time) { const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }, time); portObj.setEventTimer(timeout); diff --git a/src/colordistancesensor.ts b/src/colordistancesensor.ts new file mode 100644 index 0000000..1eecb5c --- /dev/null +++ b/src/colordistancesensor.ts @@ -0,0 +1,12 @@ +import { Device } from "./device"; +import { Hub } from "./hub"; + +import * as Consts from "./consts"; + +export class ColorDistanceSensor extends Device { + + constructor (hub: Hub, portId: number) { + super(hub, portId, Consts.DeviceType.COLOR_DISTANCE_SENSOR); + } + +} diff --git a/src/consts.ts b/src/consts.ts index dac8b22..abb7960 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -52,7 +52,7 @@ export const HubTypeNames = HubType; */ export enum DeviceType { UNKNOWN = 0, - BASIC_MOTOR = 1, + SIMPLE_MEDIUM_LINEAR_MOTOR = 1, TRAIN_MOTOR = 2, LED_LIGHTS = 8, VOLTAGE = 20, @@ -61,7 +61,7 @@ export enum DeviceType { RGB_LIGHT = 23, WEDO2_TILT = 34, WEDO2_DISTANCE = 35, - BOOST_DISTANCE = 37, + COLOR_DISTANCE_SENSOR = 37, BOOST_TACHO_MOTOR = 38, BOOST_MOVE_HUB_MOTOR = 39, BOOST_TILT = 40, diff --git a/src/controlplushub.ts b/src/controlplushub.ts index fbea784..4a0abf1 100644 --- a/src/controlplushub.ts +++ b/src/controlplushub.ts @@ -6,7 +6,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("ControlPlusHub"); @@ -36,7 +36,7 @@ export class ControlPlusHub extends LPF2Hub { protected _voltageMaxRaw = 4095; protected _voltageMaxV = 9.615; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(device, autoSubscribe); this.type = Consts.HubType.CONTROL_PLUS_HUB; this._ports = { @@ -59,7 +59,7 @@ export class ControlPlusHub extends LPF2Hub { return new Promise(async (resolve, reject) => { debug("Connecting to Control+ Hub"); await super.connect(); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3d, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01])); // Temperature + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3d, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01])); // Temperature debug("Connect completed"); return resolve(); }); @@ -107,17 +107,17 @@ export class ControlPlusHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } data.writeUInt16LE(time > 65535 ? 65535 : time, 4); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; } else { // @ts-ignore: The type of speed is properly checked at the start const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); // @ts-ignore: The type of time is properly checked at the start }, time); @@ -135,14 +135,14 @@ export class ControlPlusHub extends LPF2Hub { // @ts-ignore: The type of speed is properly checked at the start data = Buffer.from([0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; } else { // @ts-ignore: The type of speed is properly checked at the start const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); } } @@ -204,7 +204,7 @@ export class ControlPlusHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } data.writeUInt32LE(angle, 4); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; @@ -241,7 +241,7 @@ export class ControlPlusHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); data.writeInt32LE(pos, 4); } - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; @@ -265,7 +265,7 @@ export class ControlPlusHub extends LPF2Hub { } return new Promise((resolve) => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }); } @@ -295,11 +295,11 @@ export class ControlPlusHub extends LPF2Hub { portObj.cancelEventTimer(); return new Promise((resolve, reject) => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); if (time) { const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }, time); portObj.setEventTimer(timeout); diff --git a/src/controlpluslargemotor.ts b/src/controlpluslargemotor.ts new file mode 100644 index 0000000..8fcccec --- /dev/null +++ b/src/controlpluslargemotor.ts @@ -0,0 +1,12 @@ +import { BasicMotor } from "./basicmotor"; +import { Hub } from "./hub"; + +import * as Consts from "./consts"; + +export class ControlPlusLargeMotor extends BasicMotor { + + constructor (hub: Hub, portId: number) { + super(hub, portId, Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR); + } + +} diff --git a/src/device.ts b/src/device.ts new file mode 100644 index 0000000..73ddd4d --- /dev/null +++ b/src/device.ts @@ -0,0 +1,45 @@ +import { EventEmitter } from "events"; +import { Hub } from "./hub"; + +import * as Consts from "./consts"; + +export class Device extends EventEmitter { + + private _hub: Hub; + private _portId: number; + private _connected: boolean = true; + private _type: number; + + constructor (hub: Hub, portId: number, type: number = Consts.DeviceType.UNKNOWN) { + super(); + this._hub = hub; + this._portId = portId; + this._type = type; + console.log(`New device on ${this._portId} - ${this._type}`); + } + + public get connected () { + return this._connected; + } + + public get hub () { + return this._hub; + } + + public get portId () { + return this._portId; + } + + public get port () { + return "A"; // TODO NK: Look up the port name from the relevant hub + } + + public get type () { + return this._type; + } + + public send (data: Buffer, characteristic: string = Consts.BLECharacteristic.LPF2_ALL, callback?: () => void) { + this.hub.send(characteristic, data, callback); + } + +} diff --git a/src/duplotrainbase.ts b/src/duplotrainbase.ts index c52ca0d..a343cdc 100644 --- a/src/duplotrainbase.ts +++ b/src/duplotrainbase.ts @@ -6,7 +6,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("duplotrainbase"); @@ -36,7 +36,7 @@ export class DuploTrainBase extends LPF2Hub { protected _voltageMaxV = 6.4; protected _voltageMaxRaw = 3047; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(device, autoSubscribe); this.type = Consts.HubType.DUPLO_TRAIN_HUB; this._ports = { @@ -80,16 +80,16 @@ export class DuploTrainBase extends LPF2Hub { return new Promise((resolve, reject) => { if (time && typeof time === "number") { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }, time); portObj.setEventTimer(timeout); } else { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); } }); @@ -138,7 +138,7 @@ export class DuploTrainBase extends LPF2Hub { public playSound (sound: number) { return new Promise((resolve, reject) => { const data = Buffer.from([0x81, 0x01, 0x11, 0x51, 0x01, sound]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }); } diff --git a/src/hub.ts b/src/hub.ts index fb48dc3..f4fd976 100644 --- a/src/hub.ts +++ b/src/hub.ts @@ -1,11 +1,12 @@ import { EventEmitter } from "events"; -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); +import { Device } from "./device"; const debug = Debug("hub"); @@ -20,6 +21,8 @@ export class Hub extends EventEmitter { public useSpeedMap: boolean = true; public type: Consts.HubType = Consts.HubType.UNKNOWN; + protected _attachedDevices: Device[] = []; + protected _ports: {[port: string]: Port} = {}; protected _virtualPorts: {[port: string]: Port} = {}; @@ -32,12 +35,12 @@ export class Hub extends EventEmitter { protected _current: number = 0; protected _rssi: number = -60; - protected _bleDevice: IBLEDevice; + protected _bleDevice: IBLEAbstraction; private _isConnecting = false; private _isConnected = false; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(); this.autoSubscribe = !!autoSubscribe; this._bleDevice = device; @@ -246,6 +249,13 @@ export class Hub extends EventEmitter { } + public send (uuid: string, message: Buffer, callback?: () => void) { + if (callback) { + callback(); + } + } + + // protected _getCharacteristic (uuid: string) { // return this._characteristics[uuid.replace(/-/g, "")]; // } @@ -277,34 +287,49 @@ export class Hub extends EventEmitter { } - protected _registerDeviceAttachment (port: Port, type: number) { + protected _registerDeviceAttachment (device: Device) { - if (port.connected) { - port.type = type; - if (this.autoSubscribe) { - this._activatePortDevice(port.value, type, this._getModeForDeviceType(type), 0x00); - } - /** - * Emits when a motor or sensor is attached to the Hub. - * @event Hub#attach - * @param {string} port - * @param {DeviceType} type - */ - this.emit("attach", port.id, type); + const exists = this._attachedDevices.find((attachedDevice) => attachedDevice.portId === device.portId); + + if (exists) { + // TODO NK: Remove existing zombie device } else { - port.type = Consts.DeviceType.UNKNOWN; - debug(`Port ${port.id} disconnected`); - /** - * Emits when an attached motor or sensor is detached from the Hub. - * @event Hub#detach - * @param {string} port - */ - if (this._virtualPorts[port.id]) { - delete this._virtualPorts[port.id]; - } - this.emit("detach", port.id); + this._attachedDevices.push(device); } + /** + * Emits when a device is attached to the Hub. + * @event Hub#attach + * @param {Device} device + */ + this.emit("attach", device); + + // if (port.connected) { + // port.type = type; + // if (this.autoSubscribe) { + // this._activatePortDevice(port.value, type, this._getModeForDeviceType(type), 0x00); + // } + // /** + // * Emits when a motor or sensor is attached to the Hub. + // * @event Hub#attach + // * @param {string} port + // * @param {DeviceType} type + // */ + // this.emit("attach", port.id, type); + // } else { + // port.type = Consts.DeviceType.UNKNOWN; + // debug(`Port ${port.id} disconnected`); + // /** + // * Emits when an attached motor or sensor is detached from the Hub. + // * @event Hub#detach + // * @param {string} port + // */ + // if (this._virtualPorts[port.id]) { + // delete this._virtualPorts[port.id]; + // } + // this.emit("detach", port.id); + // } + } @@ -388,7 +413,7 @@ export class Hub extends EventEmitter { private _getModeForDeviceType (type: Consts.DeviceType) { switch (type) { - case Consts.DeviceType.BASIC_MOTOR: + case Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR: return 0x02; case Consts.DeviceType.TRAIN_MOTOR: return 0x02; @@ -404,7 +429,7 @@ export class Hub extends EventEmitter { return 0x00; case Consts.DeviceType.CONTROL_PLUS_ACCELEROMETER: return 0x00; - case Consts.DeviceType.BOOST_DISTANCE: + case Consts.DeviceType.COLOR_DISTANCE_SENSOR: return (this.type === Consts.HubType.WEDO2_SMART_HUB ? 0x00 : 0x08); case Consts.DeviceType.BOOST_TILT: return 0x04; diff --git a/src/index-browser.ts b/src/index-browser.ts index af7b158..d1310d1 100644 --- a/src/index-browser.ts +++ b/src/index-browser.ts @@ -1,15 +1,35 @@ import * as Consts from "./consts"; +import { PoweredUP } from "./poweredup-browser"; + import { BoostMoveHub } from "./boostmovehub"; import { ControlPlusHub } from "./controlplushub"; import { DuploTrainBase } from "./duplotrainbase"; import { Hub } from "./hub"; -import { PoweredUP } from "./poweredup-browser"; import { PUPHub } from "./puphub"; import { PUPRemote } from "./pupremote"; import { WeDo2SmartHub } from "./wedo2smarthub"; +import { ColorDistanceSensor } from "./colordistancesensor"; +import { ControlPlusLargeMotor } from "./controlpluslargemotor"; +import { Device } from "./device"; + import { isWebBluetooth } from "./utils"; // @ts-ignore -window.PoweredUP = { PoweredUP, Hub, WeDo2SmartHub, BoostMoveHub, ControlPlusHub, PUPHub, PUPRemote, DuploTrainBase, Consts, isWebBluetooth }; +window.PoweredUP = { + PoweredUP, + Hub, + WeDo2SmartHub, + BoostMoveHub, + ControlPlusHub, + PUPHub, + PUPRemote, + DuploTrainBase, + Consts, + Device, + ColorDistanceSensor, + ControlPlusLargeMotor, + isWebBluetooth +}; + diff --git a/src/index-node.ts b/src/index-node.ts index 3d5c7ac..8805138 100644 --- a/src/index-node.ts +++ b/src/index-node.ts @@ -1,15 +1,34 @@ import * as Consts from "./consts"; +import { PoweredUP } from "./poweredup-node"; + import { BoostMoveHub } from "./boostmovehub"; import { ControlPlusHub } from "./controlplushub"; import { DuploTrainBase } from "./duplotrainbase"; import { Hub } from "./hub"; -import { PoweredUP } from "./poweredup-node"; import { PUPHub } from "./puphub"; import { PUPRemote } from "./pupremote"; import { WeDo2SmartHub } from "./wedo2smarthub"; +import { ColorDistanceSensor } from "./colordistancesensor"; +import { ControlPlusLargeMotor } from "./controlpluslargemotor"; +import { Device } from "./device"; + import { isWebBluetooth } from "./utils"; export default PoweredUP; -export { PoweredUP, Hub, WeDo2SmartHub, BoostMoveHub, ControlPlusHub, PUPHub, PUPRemote, DuploTrainBase, Consts, isWebBluetooth }; +export { + PoweredUP, + Hub, + WeDo2SmartHub, + BoostMoveHub, + ControlPlusHub, + PUPHub, + PUPRemote, + DuploTrainBase, + Consts, + Device, + ColorDistanceSensor, + ControlPlusLargeMotor, + isWebBluetooth +}; diff --git a/src/interfaces.ts b/src/interfaces.ts index efebe43..cdb1bce 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,6 +1,6 @@ import { EventEmitter } from "events"; -export interface IBLEDevice extends EventEmitter { +export interface IBLEAbstraction extends EventEmitter { uuid: string; name: string; connecting: boolean; diff --git a/src/lpf2hub.ts b/src/lpf2hub.ts index 3f9c658..9593682 100644 --- a/src/lpf2hub.ts +++ b/src/lpf2hub.ts @@ -1,8 +1,10 @@ -import { Peripheral } from "@abandonware/noble"; - +import { Device } from "./device"; import { Hub } from "./hub"; import { Port } from "./port"; +import { ColorDistanceSensor } from "./colordistancesensor"; +import { ControlPlusLargeMotor } from "./controlpluslargemotor"; + import * as Consts from "./consts"; import { toBin, toHex } from "./utils"; @@ -46,21 +48,21 @@ export class LPF2Hub extends Hub { await this._bleDevice.discoverCharacteristicsForService(Consts.BLEService.LPF2_HUB); this._bleDevice.subscribeToCharacteristic(Consts.BLECharacteristic.LPF2_ALL, this._parseMessage.bind(this)); if (this._voltagePort !== undefined) { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, this._voltagePort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate voltage reports + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, this._voltagePort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate voltage reports } if (this._currentPort !== undefined) { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, this._currentPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate current reports + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, this._currentPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate current 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])); + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01])); } await this.sleep(100); - 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])); // Request firmware version - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x04, 0x05])); // Request hardware version - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x05, 0x02])); // Activate RSSI updates - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x06, 0x02])); // Activate battery level reports - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x0d, 0x05])); // Request primary MAC address + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x02, 0x02])); // Activate button reports + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x03, 0x05])); // Request firmware version + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x04, 0x05])); // Request hardware version + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x05, 0x02])); // Activate RSSI updates + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x06, 0x02])); // Activate battery level reports + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x0d, 0x05])); // Request primary MAC address this.emit("connect"); resolve(); }); @@ -74,7 +76,7 @@ export class LPF2Hub extends Hub { */ public shutdown () { return new Promise((resolve, reject) => { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x02, 0x01]), () => { + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x02, 0x01]), () => { return resolve(); }); }); @@ -95,8 +97,8 @@ export class LPF2Hub extends Hub { let data = Buffer.from([0x01, 0x01, 0x01]); data = Buffer.concat([data, Buffer.from(name, "ascii")]); // Send this twice, as sometimes the first time doesn't take - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); this._name = name; return resolve(); }); @@ -112,12 +114,12 @@ export class LPF2Hub extends Hub { public setLEDColor (color: number | boolean) { return new Promise((resolve, reject) => { let data = Buffer.from([0x41, this._ledPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); if (typeof color === "boolean") { color = 0; } data = Buffer.from([0x81, this._ledPort, 0x11, 0x51, 0x00, color]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }); } @@ -134,9 +136,9 @@ export class LPF2Hub extends Hub { public setLEDRGB (red: number, green: number, blue: number) { return new Promise((resolve, reject) => { let data = Buffer.from([0x41, this._ledPort, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); data = Buffer.from([0x81, this._ledPort, 0x11, 0x51, 0x01, red, green, blue]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }); } @@ -144,24 +146,14 @@ export class LPF2Hub extends Hub { public sendRaw (message: Buffer) { return new Promise((resolve, reject) => { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, message, () => { + this.send(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); - } - - - protected _deactivatePortDevice (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, 0x00]), callback); - } - - - protected _writeMessage (uuid: string, message: Buffer, callback?: () => void) { + public send (uuid: string, message: Buffer, callback?: () => void) { message = Buffer.concat([Buffer.alloc(2), message]); message[0] = message.length; debug("Sent Message (LPF2_ALL)", message); @@ -169,6 +161,16 @@ export class LPF2Hub extends Hub { } + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), callback); + } + + + protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x00]), callback); + } + + protected _combinePorts (port: string, type: number) { if (!this._ports[port]) { return; @@ -178,7 +180,7 @@ export class LPF2Hub extends Hub { Object.keys(this._ports).forEach((id) => { if (this._ports[id].type === type && this._ports[id].value !== portObj.value && !this._virtualPorts[`${portObj.value < this._ports[id].value ? portObj.id : this._ports[id].id}${portObj.value > this._ports[id].value ? portObj.id : this._ports[id].id}`]) { debug("Combining ports", portObj.value < this._ports[id].value ? portObj.id : id, portObj.value > this._ports[id].value ? portObj.id : id); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x61, 0x01, portObj.value < this._ports[id].value ? portObj.value : this._ports[id].value, portObj.value > this._ports[id].value ? portObj.value : this._ports[id].value])); + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x61, 0x01, portObj.value < this._ports[id].value ? portObj.value : this._ports[id].value, portObj.value > this._ports[id].value ? portObj.value : this._ports[id].value])); } }); } @@ -291,48 +293,73 @@ export class LPF2Hub extends Hub { private _parsePortMessage (data: Buffer) { - let port = this._getPortForPortNumber(data[3]); - const type = data[4] ? data.readUInt16LE(5) : 0; + const portId = data[3]; + const event = data[4]; + const deviceType = event ? data.readUInt16LE(5) : 0; - if (data[4] === 0x01 && modeInfoDebug.enabled) { - const typeName = Consts.DeviceTypeNames[data[5]] || "unknown"; - modeInfoDebug(`Port ${toHex(data[3])}, type ${toHex(type, 4)} (${typeName})`); - const hwVersion = LPF2Hub.decodeVersion(data.readInt32LE(7)); - const swVersion = LPF2Hub.decodeVersion(data.readInt32LE(11)); - modeInfoDebug(`Port ${toHex(data[3])}, hardware version ${hwVersion}, software version ${swVersion}`); - this._sendPortInformationRequest(data[3]); - } + if (event === 0x01) { - if (!port) { - if (data[4] === 0x02) { - const portA = this._getPortForPortNumber(data[7]); - const portB = this._getPortForPortNumber(data[8]); - if (portA && portB) { - this._virtualPorts[`${portA.id}${portB.id}`] = new Port(`${portA.id}${portB.id}`, data[3]); - port = this._getPortForPortNumber(data[3]); - if (port) { - port.connected = true; - this._registerDeviceAttachment(port, type); - } else { - return; - } - } else { - return; - } - } else { - return; + let device; + + switch (deviceType) { + case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: + device = new ControlPlusLargeMotor(this, portId); + break; + case Consts.DeviceType.COLOR_DISTANCE_SENSOR: + device = new ColorDistanceSensor(this, portId); + break; + default: + device = new Device(this, portId, deviceType); + break; } - } else { - port.connected = (data[4] === 0x01 || data[4] === 0x02) ? true : false; - this._registerDeviceAttachment(port, type); + + this._registerDeviceAttachment(device); + } + + + // let port = this._getPortForPortNumber(data[3]); + + // if (data[4] === 0x01 && modeInfoDebug.enabled) { + // const typeName = Consts.DeviceTypeNames[data[5]] || "unknown"; + // modeInfoDebug(`Port ${toHex(data[3])}, type ${toHex(deviceType, 4)} (${typeName})`); + // const hwVersion = LPF2Hub.decodeVersion(data.readInt32LE(7)); + // const swVersion = LPF2Hub.decodeVersion(data.readInt32LE(11)); + // modeInfoDebug(`Port ${toHex(data[3])}, hardware version ${hwVersion}, software version ${swVersion}`); + // this._sendPortInformationRequest(data[3]); + // } + + // if (!port) { + // if (data[4] === 0x02) { + // const portA = this._getPortForPortNumber(data[7]); + // const portB = this._getPortForPortNumber(data[8]); + // if (portA && portB) { + // this._virtualPorts[`${portA.id}${portB.id}`] = new Port(`${portA.id}${portB.id}`, data[3]); + // port = this._getPortForPortNumber(data[3]); + // if (port) { + // port.connected = true; + // this._registerDeviceAttachment(port, deviceType); + // } else { + // return; + // } + // } else { + // return; + // } + // } else { + // return; + // } + // } else { + // port.connected = (data[4] === 0x01 || data[4] === 0x02) ? true : false; + // this._registerDeviceAttachment(port, deviceType); + // } + } private _sendPortInformationRequest (port: number) { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x21, port, 0x01])); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x21, port, 0x02])); // Mode combinations + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x21, port, 0x01])); + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x21, port, 0x02])); // Mode combinations } @@ -363,7 +390,7 @@ export class LPF2Hub extends Hub { private _sendModeInformationRequest (port: number, mode: number, type: number) { - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x22, port, mode, type])); + this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x22, port, mode, type])); } @@ -461,7 +488,7 @@ export class LPF2Hub extends Hub { this.emit("distance", port.id, distance * 10); break; } - case Consts.DeviceType.BOOST_DISTANCE: { + case Consts.DeviceType.COLOR_DISTANCE_SENSOR: { /** * Emits when a color sensor is activated. diff --git a/src/nobledevice.ts b/src/nobleabstraction.ts similarity index 97% rename from src/nobledevice.ts rename to src/nobleabstraction.ts index 5b30d30..d9a6f83 100644 --- a/src/nobledevice.ts +++ b/src/nobleabstraction.ts @@ -2,11 +2,11 @@ import { Characteristic, Peripheral, Service } from "@abandonware/noble"; import Debug = require("debug"); import { EventEmitter } from "events"; -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("bledevice"); -export class NobleDevice extends EventEmitter implements IBLEDevice { +export class NobleDevice extends EventEmitter implements IBLEAbstraction { private _noblePeripheral: Peripheral; diff --git a/src/poweredup-browser.ts b/src/poweredup-browser.ts index d6c4c6a..67f4140 100644 --- a/src/poweredup-browser.ts +++ b/src/poweredup-browser.ts @@ -4,7 +4,7 @@ import { DuploTrainBase } from "./duplotrainbase"; import { Hub } from "./hub"; import { PUPHub } from "./puphub"; import { PUPRemote } from "./pupremote"; -import { WebBLEDevice } from "./webbledevice"; +import { WebBLEDevice } from "./webbleabstraction"; import { WeDo2SmartHub } from "./wedo2smarthub"; import * as Consts from "./consts"; @@ -12,7 +12,7 @@ import * as Consts from "./consts"; import { EventEmitter } from "events"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("poweredup"); @@ -118,7 +118,7 @@ export class PoweredUP extends EventEmitter { } - private _determineLPF2HubType (device: IBLEDevice): Promise { + private _determineLPF2HubType (device: IBLEAbstraction): Promise { return new Promise((resolve, reject) => { let buf: Buffer = Buffer.alloc(0); device.subscribeToCharacteristic(Consts.BLECharacteristic.LPF2_ALL, (data: Buffer) => { diff --git a/src/poweredup-node.ts b/src/poweredup-node.ts index fb9ea1d..e9a8d82 100644 --- a/src/poweredup-node.ts +++ b/src/poweredup-node.ts @@ -4,7 +4,7 @@ import { BoostMoveHub } from "./boostmovehub"; import { ControlPlusHub } from "./controlplushub"; import { DuploTrainBase } from "./duplotrainbase"; import { Hub } from "./hub"; -import { NobleDevice } from "./nobledevice"; +import { NobleDevice } from "./nobleabstraction"; import { PUPHub } from "./puphub"; import { PUPRemote } from "./pupremote"; import { WeDo2SmartHub } from "./wedo2smarthub"; diff --git a/src/puphub.ts b/src/puphub.ts index a305511..f718d5e 100644 --- a/src/puphub.ts +++ b/src/puphub.ts @@ -7,7 +7,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("puphub"); @@ -34,7 +34,7 @@ export class PUPHub extends LPF2Hub { protected _currentPort = 0x3b; protected _voltagePort = 0x3c; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(device, autoSubscribe); this.type = Consts.HubType.POWERED_UP_HUB; this._ports = { @@ -99,17 +99,17 @@ export class PUPHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } data.writeUInt16LE(time > 65535 ? 65535 : time, 4); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; } else { // @ts-ignore: The type of speed is properly checked at the start const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); // @ts-ignore: The type of time is properly checked at the start }, time); @@ -127,14 +127,14 @@ export class PUPHub extends LPF2Hub { // @ts-ignore: The type of speed is properly checked at the start data = Buffer.from([0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; } else { // @ts-ignore: The type of speed is properly checked at the start const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); } } @@ -196,7 +196,7 @@ export class PUPHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); } data.writeUInt32LE(angle, 4); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; @@ -233,7 +233,7 @@ export class PUPHub extends LPF2Hub { data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]); data.writeInt32LE(pos, 4); } - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); portObj.finished = () => { return resolve(); }; @@ -257,23 +257,12 @@ export class PUPHub extends LPF2Hub { } return new Promise((resolve) => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }); } - /** - * Fully (hard) stop the motor on a given port. - * @method PUPHub#brakeMotor - * @param {string} port - * @returns {Promise} Resolved upon successful completion of command. - */ - public brakeMotor (port: string) { - return this.setMotorSpeed(port, 127); - } - - /** * Set the light brightness on a given port. * @method PUPHub#setLightBrightness @@ -287,11 +276,11 @@ export class PUPHub extends LPF2Hub { portObj.cancelEventTimer(); return new Promise((resolve, reject) => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); if (time) { const timeout = global.setTimeout(() => { const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]); - this._writeMessage(Consts.BLECharacteristic.LPF2_ALL, data); + this.send(Consts.BLECharacteristic.LPF2_ALL, data); return resolve(); }, time); portObj.setEventTimer(timeout); diff --git a/src/pupremote.ts b/src/pupremote.ts index d01c3f2..c6fcecf 100644 --- a/src/pupremote.ts +++ b/src/pupremote.ts @@ -6,7 +6,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("pupremote"); @@ -37,7 +37,7 @@ export class PUPRemote extends LPF2Hub { protected _voltageMaxRaw = 3200; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(device, autoSubscribe); this.type = Consts.HubType.POWERED_UP_REMOTE; this._ports = { diff --git a/src/simplemediumlinearmotor.ts b/src/simplemediumlinearmotor.ts new file mode 100644 index 0000000..824b0f3 --- /dev/null +++ b/src/simplemediumlinearmotor.ts @@ -0,0 +1,12 @@ +import { BasicMotor } from "./basicmotor"; +import { Hub } from "./hub"; + +import * as Consts from "./consts"; + +export class SimpleMediumLinearMotor extends BasicMotor { + + constructor (hub: Hub, portId: number) { + super(hub, portId, Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR); + } + +} diff --git a/src/trainmotor.ts b/src/trainmotor.ts new file mode 100644 index 0000000..6f590a6 --- /dev/null +++ b/src/trainmotor.ts @@ -0,0 +1,12 @@ +import { BasicMotor } from "./basicmotor"; +import { Hub } from "./hub"; + +import * as Consts from "./consts"; + +export class TrainMotor extends BasicMotor { + + constructor (hub: Hub, portId: number) { + super(hub, portId, Consts.DeviceType.TRAIN_MOTOR); + } + +} diff --git a/src/webbledevice.ts b/src/webbleabstraction.ts similarity index 97% rename from src/webbledevice.ts rename to src/webbleabstraction.ts index cf8a337..0380191 100644 --- a/src/webbledevice.ts +++ b/src/webbleabstraction.ts @@ -1,10 +1,10 @@ import Debug = require("debug"); import { EventEmitter } from "events"; -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; const debug = Debug("bledevice"); -export class WebBLEDevice extends EventEmitter implements IBLEDevice { +export class WebBLEDevice extends EventEmitter implements IBLEAbstraction { private _webBLEServer: any; diff --git a/src/wedo2smarthub.ts b/src/wedo2smarthub.ts index 1e7ecb7..e08a99a 100644 --- a/src/wedo2smarthub.ts +++ b/src/wedo2smarthub.ts @@ -1,12 +1,16 @@ import { Peripheral } from "@abandonware/noble"; +import { Device } from "./device"; import { Hub } from "./hub"; import { Port } from "./port"; +import { ColorDistanceSensor } from "./colordistancesensor"; +import { ControlPlusLargeMotor } from "./controlpluslargemotor"; + import * as Consts from "./consts"; import Debug = require("debug"); -import { IBLEDevice } from "./interfaces"; +import { IBLEAbstraction } from "./interfaces"; import { isWebBluetooth } from "./utils"; const debug = Debug("wedo2smarthub"); @@ -32,7 +36,7 @@ export class WeDo2SmartHub extends Hub { private _lastTiltY: number = 0; - constructor (device: IBLEDevice, autoSubscribe: boolean = true) { + constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) { super(device, autoSubscribe); this.type = Consts.HubType.WEDO2_SMART_HUB; this._ports = { @@ -111,8 +115,8 @@ export class WeDo2SmartHub extends Hub { return new Promise((resolve, reject) => { const data = Buffer.from(name, "ascii"); // Send this twice, as sometimes the first time doesn't take - this._writeMessage(Consts.BLECharacteristic.WEDO2_NAME_ID, data); - this._writeMessage(Consts.BLECharacteristic.WEDO2_NAME_ID, data); + this.send(Consts.BLECharacteristic.WEDO2_NAME_ID, data); + this.send(Consts.BLECharacteristic.WEDO2_NAME_ID, data); this._name = name; return resolve(); }); @@ -128,12 +132,12 @@ export class WeDo2SmartHub extends Hub { public setLEDColor (color: number | boolean) { return new Promise((resolve, reject) => { let data = Buffer.from([0x06, 0x17, 0x01, 0x01]); - this._writeMessage(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, data); if (typeof color === "boolean") { color = 0; } data = Buffer.from([0x06, 0x04, 0x01, color]); - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); return resolve(); }); } @@ -146,7 +150,7 @@ export class WeDo2SmartHub extends Hub { */ public shutdown () { return new Promise((resolve, reject) => { - this._writeMessage(Consts.BLECharacteristic.WEDO2_DISCONNECT, Buffer.from([0x00]), () => { + this.send(Consts.BLECharacteristic.WEDO2_DISCONNECT, Buffer.from([0x00]), () => { return resolve(); }); }); @@ -164,9 +168,9 @@ export class WeDo2SmartHub extends Hub { public setLEDRGB (red: number, green: number, blue: number) { return new Promise((resolve, reject) => { let data = Buffer.from([0x06, 0x17, 0x01, 0x02]); - this._writeMessage(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, data); data = Buffer.from([0x06, 0x04, 0x03, red, green, blue]); - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); return resolve(); }); } @@ -193,10 +197,10 @@ export class WeDo2SmartHub extends Hub { portObj.cancelEventTimer(); } return new Promise((resolve, reject) => { - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([portObj.value, 0x01, 0x02, this._mapSpeed(speed)])); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([portObj.value, 0x01, 0x02, this._mapSpeed(speed)])); if (time && typeof time === "number") { const timeout = global.setTimeout(() => { - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([portObj.value, 0x01, 0x02, 0x00])); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([portObj.value, 0x01, 0x02, 0x00])); return resolve(); }, time); portObj.setEventTimer(timeout); @@ -252,7 +256,7 @@ export class WeDo2SmartHub extends Hub { const data = Buffer.from([0x05, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00]); data.writeUInt16LE(frequency, 3); data.writeUInt16LE(time, 5); - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); global.setTimeout(resolve, time); }); } @@ -271,11 +275,11 @@ export class WeDo2SmartHub extends Hub { portObj.cancelEventTimer(); return new Promise((resolve, reject) => { const data = Buffer.from([portObj.value, 0x01, 0x02, brightness]); - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); if (time) { const timeout = global.setTimeout(() => { const data = Buffer.from([portObj.value, 0x01, 0x02, 0x00]); - this._writeMessage(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); + this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data); return resolve(); }, time); portObj.setEventTimer(timeout); @@ -286,26 +290,7 @@ 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); - } - - - protected _deactivatePortDevice (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, 0x00]), callback); - } - - - private _writeMessage (uuid: string, message: Buffer, callback?: () => void) { + public send (uuid: string, message: Buffer, callback?: () => void) { if (debug.enabled) { debug(`Sent Message (${this._getCharacteristicNameFromUUID(uuid)})`, message); } @@ -313,6 +298,16 @@ export class WeDo2SmartHub extends Hub { } + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { + this.send(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), callback); + } + + + protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { + this.send(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x00]), callback); + } + + private _getCharacteristicNameFromUUID (uuid: string) { const keys = Object.keys(Consts.BLECharacteristic); for (let i = 0; i < keys.length; i++) { @@ -346,14 +341,38 @@ export class WeDo2SmartHub extends Hub { debug("Received Message (WEDO2_PORT_TYPE)", data); - const port = this._getPortForPortNumber(data[0]); + const portId = data[0]; + const event = data[1]; + const deviceType = event ? data[3] : 0; + + if (event === 0x01) { + + let device; + + switch (deviceType) { + case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: + device = new ControlPlusLargeMotor(this, portId); + break; + case Consts.DeviceType.COLOR_DISTANCE_SENSOR: + device = new ColorDistanceSensor(this, portId); + break; + default: + device = new Device(this, portId); + break; + } + + this._registerDeviceAttachment(device); - if (!port) { - return; } - port.connected = data[1] === 1 ? true : false; - this._registerDeviceAttachment(port, data[3]); + // const port = this._getPortForPortNumber(data[0]); + + // if (!port) { + // return; + // } + + // port.connected = data[1] === 1 ? true : false; + // this._registerDeviceAttachment(port, data[3]); } @@ -408,7 +427,7 @@ export class WeDo2SmartHub extends Hub { this.emit("distance", port.id, distance * 10); break; } - case Consts.DeviceType.BOOST_DISTANCE: { + case Consts.DeviceType.COLOR_DISTANCE_SENSOR: { const distance = data[2]; /** * Emits when a color sensor is activated.