diff --git a/ABOUT.md b/ABOUT.md
index 5f469c0..5da516e 100644
--- a/ABOUT.md
+++ b/ABOUT.md
@@ -24,7 +24,11 @@ While most LPF2 components and Hubs are compatible with each other, there are ex
| Boost Color and Distance Sensor | Sensor | *Partial (1)* | Yes | Yes | 17101 |
| Boost Interactive Motor | Motor/Sensor | *Partial (2)* | Yes | Yes | 17101 |
| Powered Up Train Motor | Motor | No | Yes | Yes | 60197
60198 |
+<<<<<<< HEAD
| Powered Up LED Lights | Lights | Unknown | Unknown | Unknown | 88005 |
+=======
+| Powered Up LED Lights | Light | Unknown | Unknown | Unknown | 88005 |
+>>>>>>> 4988da178b8c48d2c76a5f026c750cf727f5f5f5
(1) Only color mode is supported on the WeDo 2.0 Smart Hub at this point.
diff --git a/README.md b/README.md
index 9224b56..45af87d 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ While most LPF2 components and Hubs are compatible with each other, there are ex
| Boost Color and Distance Sensor | Sensor | *Partial (1)* | Yes | Yes | 17101 |
| Boost Interactive Motor | Motor/Sensor | *Partial (2)* | Yes | Yes | 17101 |
| Powered Up Train Motor | Motor | No | Yes | Yes | 60197
60198 |
-| Powered Up LED Lights | Lights | Unknown | Unknown | Unknown | 88005 |
+| Powered Up LED Lights | Light | Unknown | Unknown | Unknown | 88005 |
(1) Only color mode is supported on the WeDo 2.0 Smart Hub at this point.
diff --git a/consts.ts b/consts.ts
index 0bdf702..601ed75 100644
--- a/consts.ts
+++ b/consts.ts
@@ -9,13 +9,15 @@ export enum Hubs {
export enum Devices {
UNKNOWN = 0,
BASIC_MOTOR = 1,
+ TRAIN_MOTOR = 2,
BOOST_LED = 22,
WEDO2_TILT = 34,
WEDO2_DISTANCE = 35,
BOOST_DISTANCE = 37,
BOOST_INTERACTIVE_MOTOR = 38,
BOOST_MOVE_HUB_MOTOR = 39,
- BOOST_TILT = 40
+ BOOST_TILT = 40,
+ REMOTE_BUTTON = 55
}
@@ -35,14 +37,16 @@ export enum Colors {
export enum ButtonStates {
PRESSED = 0,
- RELEASED = 1
+ RELEASED = 1,
+ UP = 2,
+ DOWN = 3,
+ STOP = 4
}
-export enum BLENames {
- WEDO2_SMART_HUB_NAME = "LPF2 Smart Hub 2 I/O",
- BOOST_MOVE_HUB_NAME = "LEGO Move Hub",
- POWERED_UP_HUB_NAME = "HUB NO.4",
- POWERED_UP_REMOTE_NAME = "Handset"
+export enum BLEManufacturerData {
+ BOOST_MOVE_HUB_ID = 64,
+ POWERED_UP_HUB_ID = 65,
+ POWERED_UP_REMOTE_ID = 66
}
export enum BLEServices {
diff --git a/examples/vernie_remote.js b/examples/vernie_remote.js
new file mode 100644
index 0000000..ed36b2a
--- /dev/null
+++ b/examples/vernie_remote.js
@@ -0,0 +1,67 @@
+const LPF2 = require("..");
+
+const lpf2 = new LPF2.LPF2();
+lpf2.scan(); // Start scanning for Vernie
+
+console.log("Looking for Vernie and Remote...");
+
+let vernie = null;
+let remote = null;
+
+lpf2.on("discover", async (hub) => { // Wait to discover Vernie and Remote
+
+ if (hub.type === LPF2.Consts.Hubs.BOOST_MOVE_HUB) {
+ vernie = hub;
+ await vernie.connect();
+ console.log("Connected to Vernie!");
+
+
+ } else if (hub.type === LPF2.Consts.Hubs.POWERED_UP_REMOTE) {
+ remote = hub;
+
+ remote.on("button", async (button, state) => {
+ if (vernie) {
+ switch (state) {
+ case LPF2.Consts.ButtonStates.UP:
+ {
+ vernie.setMotorSpeed(button === "LEFT" ? "A" : "B", 50);
+ break;
+ }
+ case LPF2.Consts.ButtonStates.DOWN:
+ {
+ vernie.setMotorSpeed(button === "LEFT" ? "A" : "B", -50);
+ break;
+ }
+ case LPF2.Consts.ButtonStates.RELEASED:
+ {
+ if (button !== "GREEN") {
+ vernie.setMotorSpeed(button === "LEFT" ? "A" : "B", 0);
+ }
+ break;
+ }
+ case LPF2.Consts.ButtonStates.STOP:
+ {
+ await vernie.setMotorAngle("D", 35, button === "LEFT" ? -20 : 20);
+ break;
+ }
+ case LPF2.Consts.ButtonStates.PRESSED:
+ {
+ if (button === "GREEN") {
+ await vernie.setMotorAngle("D", 80, 20);
+ await vernie.setMotorAngle("D", 80, -20);
+ }
+ break;
+ }
+ }
+ }
+ })
+
+ await remote.connect();
+ console.log("Connected to Powered Up Remote!");
+ }
+
+ if (vernie && remote) {
+ console.log("You're now ready to go!");
+ }
+
+});
\ No newline at end of file
diff --git a/hub.ts b/hub.ts
index 6ecee48..3d92d2e 100644
--- a/hub.ts
+++ b/hub.ts
@@ -276,6 +276,8 @@ export class Hub extends EventEmitter {
switch (type) {
case Consts.Devices.BASIC_MOTOR:
return 0x02;
+ case Consts.Devices.TRAIN_MOTOR:
+ return 0x02;
case Consts.Devices.BOOST_INTERACTIVE_MOTOR:
return 0x02;
case Consts.Devices.BOOST_MOVE_HUB_MOTOR:
@@ -284,6 +286,8 @@ export class Hub extends EventEmitter {
return (this.type === Consts.Hubs.WEDO2_SMART_HUB ? 0x00 : 0x08);
case Consts.Devices.BOOST_TILT:
return 0x04;
+ case Consts.Devices.REMOTE_BUTTON:
+ return 0x00;
default:
return 0x00;
}
diff --git a/lpf2.ts b/lpf2.ts
index cad88c4..8493bb4 100644
--- a/lpf2.ts
+++ b/lpf2.ts
@@ -64,8 +64,6 @@ export class LPF2 extends EventEmitter {
return;
}
- console.log(peripheral);
-
peripheral.removeAllListeners();
noble.stopScanning();
noble.startScanning();
diff --git a/lpf2hub.ts b/lpf2hub.ts
index ba29675..7f7277c 100644
--- a/lpf2hub.ts
+++ b/lpf2hub.ts
@@ -25,24 +25,31 @@ export class LPF2Hub extends Hub {
private _lastTiltX: number = 0;
private _lastTiltY: number = 0;
+ private _incomingData: Buffer = Buffer.alloc(0);
+ private _outgoingData: Buffer = Buffer.alloc(0);
+
constructor (peripheral: Peripheral, autoSubscribe: boolean = true) {
super(peripheral, autoSubscribe);
- switch (peripheral.advertisement.localName) {
- case Consts.BLENames.POWERED_UP_HUB_NAME:
+ switch (peripheral.advertisement.manufacturerData[3]) {
+ case Consts.BLEManufacturerData.POWERED_UP_HUB_ID:
{
this.type = Consts.Hubs.POWERED_UP_HUB;
this._ports = {
- "A": new Port("A", 55),
- "B": new Port("B", 56),
+ "A": new Port("A", 0),
+ "B": new Port("B", 1),
"AB": new Port("AB", 57)
};
debug("Discovered Powered Up Hub");
break;
}
- case Consts.BLENames.POWERED_UP_REMOTE_NAME:
+ case Consts.BLEManufacturerData.POWERED_UP_REMOTE_ID:
{
this.type = Consts.Hubs.POWERED_UP_REMOTE;
+ this._ports = {
+ "LEFT": new Port("LEFT", 0),
+ "RIGHT": new Port("RIGHT", 1)
+ };
debug("Discovered Powered Up Remote");
break;
}
@@ -66,11 +73,11 @@ export class LPF2Hub extends Hub {
public connect () {
return new Promise(async (resolve, reject) => {
- debug("Connecting to Boost Move Hub");
+ debug("Connecting to Hub");
await super.connect();
const characteristic = this._characteristics[Consts.BLECharacteristics.BOOST_ALL];
this._subscribeToCharacteristic(characteristic, this._parseMessage.bind(this));
- characteristic.write(Buffer.from([0x05, 0x00, 0x01, 0x02, 0x02]), false);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, Buffer.from([0x05, 0x00, 0x01, 0x02, 0x02]));
debug("Connect completed");
return resolve();
});
@@ -85,32 +92,18 @@ export class LPF2Hub extends Hub {
*/
public setLEDColor (color: number | boolean) {
return new Promise((resolve, reject) => {
- const characteristic = this._characteristics[Consts.BLECharacteristics.BOOST_ALL];
- if (characteristic) {
- let data = Buffer.from([0x05, 0x00, 0x01, 0x02, 0x02]);
- characteristic.write(data, false);
- if (color === false) {
- color = 0;
- }
- data = Buffer.from([0x08, 0x00, 0x81, 0x32, 0x11, 0x51, 0x00, color]);
- characteristic.write(data, false);
+ let data = Buffer.from([0x05, 0x00, 0x01, 0x02, 0x02]);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, data);
+ if (color === false) {
+ color = 0;
}
+ data = Buffer.from([0x08, 0x00, 0x81, 0x32, 0x11, 0x51, 0x00, color]);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, data);
return resolve();
});
}
- // setLEDRGB (red, green, blue) {
- // const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL];
- // if (characteristic) {
- // let data = Buffer.from([0x05, 0x00, 0x01, 0x02, 0x03]);
- // characteristic.write(data);
- // data = Buffer.from([0x0a, 0x00, 0x81, 0x32, 0x11, 0x51, 0x00, red, green, blue]);
- // characteristic.write(data);
- // }
- // }
-
-
/**
* Set the motor speed on a given port.
* @method LPF2Hub#setMotorSpeed
@@ -121,22 +114,23 @@ export class LPF2Hub extends Hub {
*/
public setMotorSpeed (port: string, speed: number, time: number) {
return new Promise((resolve, reject) => {
- const characteristic = this._characteristics[Consts.BLECharacteristics.BOOST_ALL];
- if (characteristic) {
- const portObj = this._ports[port];
- if (time) {
- portObj.busy = true;
- const data = Buffer.from([0x0c, 0x00, 0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
- data.writeUInt16LE(time > 65535 ? 65535 : time, 6);
- characteristic.write(data, false);
- portObj.finished = () => {
- return resolve();
- };
- } else {
- const data = Buffer.from([0x0a, 0x00, 0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
- characteristic.write(data, false);
+ const portObj = this._ports[port];
+ if (portObj.type === Consts.Devices.TRAIN_MOTOR) {
+ const data = Buffer.from([0x08, 0x00, 0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, data);
+ return resolve();
+ } else if (time) {
+ portObj.busy = true;
+ const data = Buffer.from([0x0c, 0x00, 0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
+ data.writeUInt16LE(time > 65535 ? 65535 : time, 6);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, data);
+ portObj.finished = () => {
return resolve();
- }
+ };
+ } else {
+ const data = Buffer.from([0x0a, 0x00, 0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, data);
+ return resolve();
}
});
}
@@ -152,61 +146,80 @@ export class LPF2Hub extends Hub {
*/
public setMotorAngle (port: string, angle: number, speed: number = 100) {
return new Promise((resolve, reject) => {
- const characteristic = this._characteristics[Consts.BLECharacteristics.BOOST_ALL];
- if (characteristic) {
- const portObj = this._ports[port];
- portObj.busy = true;
- const data = Buffer.from([0x0e, 0x00, 0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0x03]);
- data.writeUInt32LE(angle, 6);
- data.writeUInt8(this._mapSpeed(speed), 10);
- characteristic.write(data, false);
- portObj.finished = () => {
- return resolve();
- };
- }
+ const portObj = this._ports[port];
+ portObj.busy = true;
+ const data = Buffer.from([0x0e, 0x00, 0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0x03]);
+ data.writeUInt32LE(angle, 6);
+ data.writeUInt8(this._mapSpeed(speed), 10);
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, data);
+ portObj.finished = () => {
+ return resolve();
+ };
});
}
protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) {
- const characteristic = this._characteristics[Consts.BLECharacteristics.BOOST_ALL];
- if (characteristic) {
- characteristic.write(Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), false, callback);
- }
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), callback);
}
protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) {
- const characteristic = this._characteristics[Consts.BLECharacteristics.BOOST_ALL];
+ this._writeMessage(Consts.BLECharacteristics.BOOST_ALL, Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x00]), callback);
+ }
+
+
+ private _writeMessage (uuid: string, message: Buffer, callback?: () => void) {
+ const characteristic = this._characteristics[uuid];
if (characteristic) {
- characteristic.write(Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x00]), false, callback);
+ characteristic.write(message, false, callback);
}
}
- private _parseMessage (data: Buffer) {
+ private _parseMessage (data?: Buffer) {
- switch (data[2]) {
- case 0x01:
- {
- this._parseDeviceInfo(data);
- break;
+ if (data) {
+ this._incomingData = Buffer.concat([this._incomingData, data]);
+ }
+
+ if (this._incomingData.length <= 0) {
+ return;
+ }
+
+ const len = this._incomingData[0];
+ if (len >= this._incomingData.length) {
+
+ const message = this._incomingData.slice(0, len);
+ this._incomingData = this._incomingData.slice(len);
+
+ switch (message[2]) {
+ case 0x01:
+ {
+ this._parseDeviceInfo(message);
+ break;
+ }
+ case 0x04:
+ {
+ this._parsePortMessage(message);
+ break;
+ }
+ case 0x45:
+ {
+ this._parseSensorMessage(message);
+ break;
+ }
+ case 0x82:
+ {
+ this._parsePortAction(message);
+ break;
+ }
}
- case 0x04:
- {
- this._parsePortMessage(data);
- break;
- }
- case 0x45:
- {
- this._parseSensorMessage(data);
- break;
- }
- case 0x82:
- {
- this._parsePortAction(data);
- break;
+
+ if (this._incomingData.length > 0) {
+ this._parseMessage();
}
+
}
}
@@ -341,6 +354,12 @@ export class LPF2Hub extends Hub {
this.emit("rotate", port.id, rotation);
break;
}
+ case Consts.Devices.BOOST_MOVE_HUB_MOTOR:
+ {
+ const rotation = data.readInt32LE(2);
+ this.emit("rotate", port.id, rotation);
+ break;
+ }
case Consts.Devices.BOOST_TILT:
{
const tiltX = data[4] > 160 ? data[4] - 255 : data[4];
@@ -348,6 +367,32 @@ export class LPF2Hub extends Hub {
this.emit("tilt", port.id, tiltX, tiltY);
break;
}
+ case Consts.Devices.REMOTE_BUTTON:
+ {
+ switch (data[4]) {
+ case 0x01:
+ {
+ this.emit("button", port.id, Consts.ButtonStates.UP);
+ break;
+ }
+ case 0xff:
+ {
+ this.emit("button", port.id, Consts.ButtonStates.DOWN);
+ break;
+ }
+ case 0x7f:
+ {
+ this.emit("button", port.id, Consts.ButtonStates.STOP);
+ break;
+ }
+ case 0x00:
+ {
+ this.emit("button", port.id, Consts.ButtonStates.RELEASED);
+ break;
+ }
+ }
+ break;
+ }
}
}
diff --git a/wedo2hub.ts b/wedo2hub.ts
index f74751e..581d414 100644
--- a/wedo2hub.ts
+++ b/wedo2hub.ts
@@ -58,18 +58,14 @@ export class WeDo2Hub extends Hub {
*/
public setLEDColor (color: number | boolean) {
return new Promise((resolve, reject) => {
- const motorCharacteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_MOTOR_VALUE_WRITE];
- const portCharacteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_PORT_TYPE_WRITE];
- if (motorCharacteristic && portCharacteristic) {
- let data = Buffer.from([0x06, 0x17, 0x01, 0x01]);
- portCharacteristic.write(data, false);
- if (color === false) {
- color = 0;
- }
- data = Buffer.from([0x06, 0x04, 0x01, color]);
- motorCharacteristic.write(data, false);
- return resolve();
+ let data = Buffer.from([0x06, 0x17, 0x01, 0x01]);
+ this._writeMessage(Consts.BLECharacteristics.WEDO2_PORT_TYPE_WRITE, data);
+ if (color === false) {
+ color = 0;
}
+ data = Buffer.from([0x06, 0x04, 0x01, color]);
+ this._writeMessage(Consts.BLECharacteristics.WEDO2_MOTOR_VALUE_WRITE, data);
+ return resolve();
});
}
@@ -84,15 +80,11 @@ export class WeDo2Hub extends Hub {
*/
public setLEDRGB (red: number, green: number, blue: number) {
return new Promise((resolve, reject) => {
- const motorCharacteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_MOTOR_VALUE_WRITE];
- const portCharacteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_PORT_TYPE_WRITE];
- if (motorCharacteristic && portCharacteristic) {
- const data1 = Buffer.from([0x01, 0x02, 0x06, 0x17, 0x01, 0x02]);
- portCharacteristic.write(data1, false);
- const data2 = Buffer.from([0x06, 0x04, 0x03, red, green, blue]);
- motorCharacteristic.write(data2, false);
- return resolve();
- }
+ let data = Buffer.from([0x01, 0x02, 0x06, 0x17, 0x01, 0x02]);
+ this._writeMessage(Consts.BLECharacteristics.WEDO2_MOTOR_VALUE_WRITE, data);
+ data = Buffer.from([0x06, 0x04, 0x03, red, green, blue]);
+ this._writeMessage(Consts.BLECharacteristics.WEDO2_PORT_TYPE_WRITE, data);
+ return resolve();
});
}
@@ -106,27 +98,26 @@ export class WeDo2Hub extends Hub {
*/
public setMotorSpeed (port: string, speed: number) {
return new Promise((resolve, reject) => {
- const characteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_MOTOR_VALUE_WRITE];
- if (characteristic) {
- characteristic.write(Buffer.from([this._ports[port].value, 0x01, 0x02, this._mapSpeed(speed)]), false);
- return resolve();
- }
+ this._writeMessage(Consts.BLECharacteristics.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([this._ports[port].value, 0x01, 0x02, this._mapSpeed(speed)]));
+ return resolve();
});
}
protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) {
- const characteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_PORT_TYPE_WRITE];
- if (characteristic) {
- characteristic.write(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), false, callback);
- }
+ this._writeMessage(Consts.BLECharacteristics.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) {
- const characteristic = this._characteristics[Consts.BLECharacteristics.WEDO2_PORT_TYPE_WRITE];
+ this._writeMessage(Consts.BLECharacteristics.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) {
+ const characteristic = this._characteristics[uuid];
if (characteristic) {
- characteristic.write(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x00]), false, callback);
+ characteristic.write(message, false, callback);
}
}