Better handling of device initialisation, implemented more modes
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Nathan Kellenicki 2019-12-16 17:07:43 -08:00
parent 2a67242f34
commit 023b141c4d
19 changed files with 205 additions and 252 deletions

View File

@ -24,12 +24,37 @@ poweredUP.on("discover", async (hub) => { // Wait to discover hubs
console.log(`Detached device ${device.type} from ${device.port}`); console.log(`Detached device ${device.type} from ${device.port}`);
}); });
if ( if ((
device instanceof PoweredUP.SimpleMediumLinearMotor ||
device instanceof PoweredUP.TrainMotor ||
device instanceof PoweredUP.MediumLinearMotor ||
device instanceof PoweredUP.TechnicLargeLinearMotor ||
device instanceof PoweredUP.TechnicXLargeLinearMotor
) && hub.type === PoweredUP.Consts.HubType.WEDO2_SMART_HUB) {
const motor = device;
motor.on("rotate", (angle) => {
console.log(`Rotate ${angle}`);
});
motor.setPower(40);
await hub.sleep(2000);
motor.setPower(0);
await hub.sleep(2000);
motor.setPower(-40);
await hub.sleep(2000);
motor.setPower(0);
await hub.sleep(2000);
motor.setPower(20);
}
if ((
// device instanceof PoweredUP.MoveHubMediumLinearMotor || // device instanceof PoweredUP.MoveHubMediumLinearMotor ||
device instanceof PoweredUP.MediumLinearMotor || device instanceof PoweredUP.MediumLinearMotor ||
device instanceof PoweredUP.TechnicLargeLinearMotor || device instanceof PoweredUP.TechnicLargeLinearMotor ||
device instanceof PoweredUP.TechnicXLargeLinearMotor device instanceof PoweredUP.TechnicXLargeLinearMotor
) { ) && hub.type !== PoweredUP.Consts.HubType.WEDO2_SMART_HUB) {
const motor = device; const motor = device;
motor.on("rotate", (angle) => { motor.on("rotate", (angle) => {
@ -85,9 +110,9 @@ poweredUP.on("discover", async (hub) => { // Wait to discover hubs
sensor.on("distance", (distance) => { sensor.on("distance", (distance) => {
console.log(`Distance ${distance}`); console.log(`Distance ${distance}`);
}); });
sensor.on("color", (color) => { // sensor.on("color", (color) => {
console.log(`Color ${color}`); // console.log(`Color ${color}`);
}); // });
} }
if (device instanceof PoweredUP.MotionSensor) { if (device instanceof PoweredUP.MotionSensor) {

View File

@ -1,11 +1,12 @@
import { Hub } from "./hub"; import { TachoMotor } from "./tachomotor";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { TachoMotor } from "./tachomotor";
export class MoveHubMediumLinearMotor extends TachoMotor { export class MoveHubMediumLinearMotor extends TachoMotor {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.MOVE_HUB_MEDIUM_LINEAR_MOTOR); super(hub, portId, Consts.DeviceType.MOVE_HUB_MEDIUM_LINEAR_MOTOR);
} }

View File

@ -1,6 +1,6 @@
import { Device } from "./device"; import { Device } from "./device";
import { Hub } from "./hub";
import { WeDo2SmartHub } from "./wedo2smarthub"; import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
@ -9,7 +9,7 @@ import { mapSpeed } from "./utils";
export class BasicMotor extends Device { export class BasicMotor extends Device {
constructor (hub: Hub, portId: number, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) { constructor (hub: IDeviceInterface, portId: number, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) {
super(hub, portId, type); super(hub, portId, type);
} }
@ -22,7 +22,8 @@ export class BasicMotor extends Device {
*/ */
public setPower (power: number) { public setPower (power: number) {
return new Promise((resolve) => { return new Promise((resolve) => {
if (this.hub instanceof WeDo2SmartHub) { const isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
if (isWeDo2) {
const data = Buffer.from([this.portId, 0x01, 0x02, mapSpeed(power)]); const data = Buffer.from([this.portId, 0x01, 0x02, mapSpeed(power)]);
this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE); this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
} else { } else {

View File

@ -1,18 +1,26 @@
import { Device } from "./device"; import { Device } from "./device";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
export class ColorDistanceSensor extends Device { export class ColorDistanceSensor extends Device {
constructor (hub: Hub, portId: number) { private _isWeDo2: boolean;
constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.COLOR_DISTANCE_SENSOR); super(hub, portId, Consts.DeviceType.COLOR_DISTANCE_SENSOR);
this._isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
this.on("newListener", (event) => { this.on("newListener", (event) => {
if (this.autoSubscribe) { if (this.autoSubscribe) {
switch (event) { switch (event) {
case "color": case "color":
this.subscribe(0x08); if (this._isWeDo2) {
this.subscribe(0x00);
} else {
this.subscribe(0x08);
}
break; break;
case "distance": case "distance":
this.subscribe(0x08); this.subscribe(0x08);
@ -28,7 +36,15 @@ export class ColorDistanceSensor extends Device {
public receive (message: Buffer) { public receive (message: Buffer) {
const mode = this._mode; const mode = this._mode;
console.log(message);
switch (mode) { switch (mode) {
case 0x00:
if (this._isWeDo2 && message[2] <= 10) {
const color = message[2];
this.emit("color", color);
}
break;
case 0x08: case 0x08:
/** /**
* Emits when a color sensor is activated. * Emits when a color sensor is activated.

View File

@ -1,5 +1,6 @@
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
@ -11,12 +12,12 @@ export class Device extends EventEmitter {
protected _busy: boolean = false; protected _busy: boolean = false;
protected _finished: (() => void) | undefined; protected _finished: (() => void) | undefined;
private _hub: Hub; private _hub: IDeviceInterface;
private _portId: number; private _portId: number;
private _connected: boolean = true; private _connected: boolean = true;
private _type: Consts.DeviceType; private _type: Consts.DeviceType;
constructor (hub: Hub, portId: number, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) { constructor (hub: IDeviceInterface, portId: number, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) {
super(); super();
this._hub = hub; this._hub = hub;
this._portId = portId; this._portId = portId;
@ -60,7 +61,7 @@ export class Device extends EventEmitter {
this._ensureConnected(); this._ensureConnected();
if (mode !== this._mode) { if (mode !== this._mode) {
this._mode = mode; this._mode = mode;
this.hub.subscribe(this.portId, mode); this.hub.subscribe(this.portId, this.type, mode);
} }
} }

View File

@ -50,7 +50,7 @@ export class DuploTrainBase extends LPF2Hub {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
debug("Connecting to Duplo Train Base"); debug("Connecting to Duplo Train Base");
await super.connect(); await super.connect();
this.subscribe(0x01, 0x01); // this.subscribe(0x01, Consts.DeviceType.DUPLO_TRAIN_BASE_SPEAKER, 0x01);
debug("Connect completed"); debug("Connect completed");
return resolve(); return resolve();
}); });

View File

@ -2,10 +2,21 @@ import { EventEmitter } from "events";
import { IBLEAbstraction } from "./interfaces"; import { IBLEAbstraction } from "./interfaces";
import { ColorDistanceSensor } from "./colordistancesensor";
import { Device } from "./device";
import { Light } from "./light";
import { MediumLinearMotor } from "./mediumlinearmotor";
import { MotionSensor } from "./motionsensor";
import { MoveHubMediumLinearMotor } from "./movehubmediumlinearmotor";
import { SimpleMediumLinearMotor } from "./simplemediumlinearmotor";
import { TechnicLargeLinearMotor } from "./techniclargelinearmotor";
import { TechnicXLargeLinearMotor } from "./technicxlargelinearmotor";
import { TiltSensor } from "./tiltsensor";
import { TrainMotor } from "./trainmotor";
import * as Consts from "./consts"; import * as Consts from "./consts";
import Debug = require("debug"); import Debug = require("debug");
import { Device } from "./device";
const debug = Debug("hub"); const debug = Debug("hub");
@ -233,7 +244,7 @@ export class Hub extends EventEmitter {
} }
public subscribe (portId: number, mode: number) { public subscribe (portId: number, deviceType: number, mode: number) {
// NK Do nothing here // NK Do nothing here
} }
@ -260,68 +271,52 @@ export class Hub extends EventEmitter {
} }
protected _createDevice (deviceType: number, portId: number) {
let device;
switch (deviceType) {
case Consts.DeviceType.LIGHT:
device = new Light(this, portId);
break;
case Consts.DeviceType.TRAIN_MOTOR:
device = new TrainMotor(this, portId);
break;
case Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR:
device = new SimpleMediumLinearMotor(this, portId);
break;
case Consts.DeviceType.MOVE_HUB_MEDIUM_LINEAR_MOTOR:
device = new MoveHubMediumLinearMotor(this, portId);
break;
case Consts.DeviceType.MOTION_SENSOR:
device = new MotionSensor(this, portId);
break;
case Consts.DeviceType.TILT_SENSOR:
device = new TiltSensor(this, portId);
break;
case Consts.DeviceType.MEDIUM_LINEAR_MOTOR:
device = new MediumLinearMotor(this, portId);
break;
case Consts.DeviceType.TECHNIC_LARGE_LINEAR_MOTOR:
device = new TechnicLargeLinearMotor(this, portId);
break;
case Consts.DeviceType.TECHNIC_XLARGE_LINEAR_MOTOR:
device = new TechnicXLargeLinearMotor(this, portId);
break;
case Consts.DeviceType.COLOR_DISTANCE_SENSOR:
device = new ColorDistanceSensor(this, portId);
break;
default:
device = new Device(this, portId, deviceType);
break;
}
return device;
}
protected _getDeviceByPortId (portId: number) { protected _getDeviceByPortId (portId: number) {
return this._attachedDevices[portId]; return this._attachedDevices[portId];
} }
// protected _calculateRamp (fromSpeed: number, toSpeed: number, time: number, port: Port) {
// const emitter = new EventEmitter();
// const steps = Math.abs(toSpeed - fromSpeed);
// let delay = time / steps;
// let increment = 1;
// if (delay < 50 && steps > 0) {
// increment = 50 / delay;
// delay = 50;
// }
// if (fromSpeed > toSpeed) {
// increment = -increment;
// }
// let i = 0;
// const interval = setInterval(() => {
// let speed = Math.round(fromSpeed + (++i * increment));
// if (toSpeed > fromSpeed && speed > toSpeed) {
// speed = toSpeed;
// } else if (fromSpeed > toSpeed && speed < toSpeed) {
// speed = toSpeed;
// }
// emitter.emit("changeSpeed", speed);
// if (speed === toSpeed) {
// clearInterval(interval);
// emitter.emit("finished");
// }
// }, delay);
// port.setEventTimer(interval);
// return emitter;
// }
// private _getModeForDeviceType (type: Consts.DeviceType) {
// switch (type) {
// case Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR:
// return 0x02;
// case Consts.DeviceType.TRAIN_MOTOR:
// return 0x02;
// case Consts.DeviceType.BOOST_TACHO_MOTOR:
// return 0x02;
// case Consts.DeviceType.BOOST_MOVE_HUB_MOTOR:
// return 0x02;
// case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR:
// return 0x02;
// case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR:
// return 0x02;
// case Consts.DeviceType.CONTROL_PLUS_TILT:
// return 0x00;
// case Consts.DeviceType.CONTROL_PLUS_ACCELEROMETER:
// return 0x00;
// case Consts.DeviceType.COLOR_DISTANCE_SENSOR:
// return (this.type === Consts.HubType.WEDO2_SMART_HUB ? 0x00 : 0x08);
// case Consts.DeviceType.BOOST_TILT:
// return 0x04;
// default:
// return 0x00;
// }
// }
} }

View File

@ -1,5 +1,7 @@
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import * as Consts from "./consts";
export interface IBLEAbstraction extends EventEmitter { export interface IBLEAbstraction extends EventEmitter {
uuid: string; uuid: string;
name: string; name: string;
@ -13,3 +15,10 @@ export interface IBLEAbstraction extends EventEmitter {
readFromCharacteristic: (uuid: string, callback: (err: string | null, data: Buffer | null) => void) => void; readFromCharacteristic: (uuid: string, callback: (err: string | null, data: Buffer | null) => void) => void;
writeToCharacteristic: (uuid: string, data: Buffer, callback?: () => void) => void; writeToCharacteristic: (uuid: string, data: Buffer, callback?: () => void) => void;
} }
export interface IDeviceInterface extends EventEmitter {
type: Consts.HubType;
getPortNameForPortId: (portId: number) => string | undefined;
send: (message: Buffer, uuid: string, callback?: () => void) => void;
subscribe: (portId: number, deviceType: number, mode: number) => void;
}

View File

@ -1,13 +1,13 @@
import { Device } from "./device"; import { Device } from "./device";
import { Hub } from "./hub";
import { WeDo2SmartHub } from "./wedo2smarthub"; import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
export class Light extends Device { export class Light extends Device {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.LIGHT); super(hub, portId, Consts.DeviceType.LIGHT);
} }
@ -20,7 +20,8 @@ export class Light extends Device {
*/ */
public setBrightness (brightness: number) { public setBrightness (brightness: number) {
return new Promise((resolve) => { return new Promise((resolve) => {
if (this.hub instanceof WeDo2SmartHub) { const isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
if (isWeDo2) {
const data = Buffer.from([this.portId, 0x01, 0x02, brightness]); const data = Buffer.from([this.portId, 0x01, 0x02, brightness]);
this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE); this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
} else { } else {

View File

@ -1,17 +1,5 @@
import { Device } from "./device";
import { Hub } from "./hub"; import { Hub } from "./hub";
import { ColorDistanceSensor } from "./colordistancesensor";
import { Light } from "./light";
import { MediumLinearMotor } from "./mediumlinearmotor";
import { MotionSensor } from "./motionsensor";
import { MoveHubMediumLinearMotor } from "./movehubmediumlinearmotor";
import { SimpleMediumLinearMotor } from "./simplemediumlinearmotor";
import { TechnicLargeLinearMotor } from "./techniclargelinearmotor";
import { TechnicXLargeLinearMotor } from "./technicxlargelinearmotor";
import { TiltSensor } from "./tiltsensor";
import { TrainMotor } from "./trainmotor";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { decodeMACAddress, decodeVersion, toBin, toHex } from "./utils"; import { decodeMACAddress, decodeVersion, toBin, toHex } from "./utils";
@ -48,10 +36,10 @@ export class LPF2Hub extends Hub {
await this._bleDevice.discoverCharacteristicsForService(Consts.BLEService.LPF2_HUB); await this._bleDevice.discoverCharacteristicsForService(Consts.BLEService.LPF2_HUB);
this._bleDevice.subscribeToCharacteristic(Consts.BLECharacteristic.LPF2_ALL, this._parseMessage.bind(this)); this._bleDevice.subscribeToCharacteristic(Consts.BLECharacteristic.LPF2_ALL, this._parseMessage.bind(this));
if (this._voltagePort !== undefined) { if (this._voltagePort !== undefined) {
this.subscribe(this._voltagePort, 0x00); // Activate voltage reports this.subscribe(this._voltagePort, Consts.DeviceType.VOLTAGE, 0x00); // Activate voltage reports
} }
if (this._currentPort !== undefined) { if (this._currentPort !== undefined) {
this.subscribe(this._currentPort, 0x00); // Activate currrent reports this.subscribe(this._currentPort, Consts.DeviceType.CURRENT, 0x00); // Activate currrent reports
} }
await this.sleep(100); await this.sleep(100);
this.send(Buffer.from([0x01, 0x02, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate button reports this.send(Buffer.from([0x01, 0x02, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate button reports
@ -149,7 +137,7 @@ export class LPF2Hub extends Hub {
} }
public subscribe (portId: number, mode: number) { public subscribe (portId: number, deviceType: number, mode: number) {
this.send(Buffer.from([0x41, portId, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL); this.send(Buffer.from([0x41, portId, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL);
} }
@ -288,44 +276,6 @@ export class LPF2Hub extends Hub {
// Handle device attachments // Handle device attachments
if (event === 0x01) { if (event === 0x01) {
let device;
switch (deviceType) {
case Consts.DeviceType.LIGHT:
device = new Light(this, portId);
break;
case Consts.DeviceType.TRAIN_MOTOR:
device = new TrainMotor(this, portId);
break;
case Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR:
device = new SimpleMediumLinearMotor(this, portId);
break;
case Consts.DeviceType.MOVE_HUB_MEDIUM_LINEAR_MOTOR:
device = new MoveHubMediumLinearMotor(this, portId);
break;
case Consts.DeviceType.MOTION_SENSOR:
device = new MotionSensor(this, portId);
break;
case Consts.DeviceType.TILT_SENSOR:
device = new TiltSensor(this, portId);
break;
case Consts.DeviceType.MEDIUM_LINEAR_MOTOR:
device = new MediumLinearMotor(this, portId);
break;
case Consts.DeviceType.TECHNIC_LARGE_LINEAR_MOTOR:
device = new TechnicLargeLinearMotor(this, portId);
break;
case Consts.DeviceType.TECHNIC_XLARGE_LINEAR_MOTOR:
device = new TechnicXLargeLinearMotor(this, portId);
break;
case Consts.DeviceType.COLOR_DISTANCE_SENSOR:
device = new ColorDistanceSensor(this, portId);
break;
default:
device = new Device(this, portId, deviceType);
break;
}
if (modeInfoDebug.enabled) { if (modeInfoDebug.enabled) {
const deviceTypeName = Consts.DeviceTypeNames[message[5]] || "Unknown"; const deviceTypeName = Consts.DeviceTypeNames[message[5]] || "Unknown";
modeInfoDebug(`Port ${toHex(portId)}, type ${toHex(deviceType, 4)} (${deviceTypeName})`); modeInfoDebug(`Port ${toHex(portId)}, type ${toHex(deviceType, 4)} (${deviceTypeName})`);
@ -335,6 +285,7 @@ export class LPF2Hub extends Hub {
this._sendPortInformationRequest(portId); this._sendPortInformationRequest(portId);
} }
const device = this._createDevice(deviceType, portId);
this._attachDevice(device); this._attachDevice(device);
// Handle device detachments // Handle device detachments

View File

@ -1,11 +1,12 @@
import { Hub } from "./hub"; import { TachoMotor } from "./tachomotor";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { TachoMotor } from "./tachomotor";
export class MediumLinearMotor extends TachoMotor { export class MediumLinearMotor extends TachoMotor {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.MEDIUM_LINEAR_MOTOR); super(hub, portId, Consts.DeviceType.MEDIUM_LINEAR_MOTOR);
} }

View File

@ -1,11 +1,12 @@
import { Device } from "./device"; import { Device } from "./device";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
export class MotionSensor extends Device { export class MotionSensor extends Device {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.MOTION_SENSOR); super(hub, portId, Consts.DeviceType.MOTION_SENSOR);
this.on("newListener", (event) => { this.on("newListener", (event) => {
@ -21,12 +22,13 @@ export class MotionSensor extends Device {
public receive (message: Buffer) { public receive (message: Buffer) {
const mode = this._mode; const mode = this._mode;
const isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
switch (mode) { switch (mode) {
case 0x00: case 0x00:
let distance = message[4]; let distance = message[isWeDo2 ? 2 : 4];
if (message[5] === 1) { if (message[isWeDo2 ? 3 : 5] === 1) {
distance = message[4] + 255; distance = distance + 255;
} }
/** /**
* Emits when a distance sensor is activated. * Emits when a distance sensor is activated.

View File

@ -1,11 +1,12 @@
import { BasicMotor } from "./basicmotor"; import { BasicMotor } from "./basicmotor";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
export class SimpleMediumLinearMotor extends BasicMotor { export class SimpleMediumLinearMotor extends BasicMotor {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR); super(hub, portId, Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR);
} }

View File

@ -1,12 +1,13 @@
import { BasicMotor } from "./basicmotor"; import { BasicMotor } from "./basicmotor";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { mapSpeed } from "./utils"; import { mapSpeed } from "./utils";
export class TachoMotor extends BasicMotor { export class TachoMotor extends BasicMotor {
constructor (hub: Hub, portId: number, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) { constructor (hub: IDeviceInterface, portId: number, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) {
super(hub, portId, type); super(hub, portId, type);
this.on("newListener", (event) => { this.on("newListener", (event) => {
@ -22,10 +23,11 @@ export class TachoMotor extends BasicMotor {
public receive (message: Buffer) { public receive (message: Buffer) {
const mode = this._mode; const mode = this._mode;
const isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
switch (mode) { switch (mode) {
case 0x02: case 0x02:
const rotation = message.readInt32LE(4); const rotation = message.readInt32LE(isWeDo2 ? 2 : 4);
/** /**
* Emits when a rotation sensor is activated. * Emits when a rotation sensor is activated.
* @event TachoMotor#rotate * @event TachoMotor#rotate
@ -44,6 +46,10 @@ export class TachoMotor extends BasicMotor {
* @returns {Promise} Resolved upon successful completion of command (ie. once the motor is finished). * @returns {Promise} Resolved upon successful completion of command (ie. once the motor is finished).
*/ */
public rotateByAngle (angle: number, power: number = 100) { public rotateByAngle (angle: number, power: number = 100) {
const isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
if (isWeDo2) {
throw new Error("Rotating by angle is not available on the WeDo 2.0 Smart Hub");
}
return new Promise((resolve) => { return new Promise((resolve) => {
this._busy = true; this._busy = true;
const message = Buffer.from([0x81, this.portId, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, mapSpeed(power), 0x64, 0x7f, 0x03]); const message = Buffer.from([0x81, this.portId, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, mapSpeed(power), 0x64, 0x7f, 0x03]);

View File

@ -1,11 +1,12 @@
import { Hub } from "./hub"; import { TachoMotor } from "./tachomotor";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { TachoMotor } from "./tachomotor";
export class TechnicLargeLinearMotor extends TachoMotor { export class TechnicLargeLinearMotor extends TachoMotor {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.TECHNIC_LARGE_LINEAR_MOTOR); super(hub, portId, Consts.DeviceType.TECHNIC_LARGE_LINEAR_MOTOR);
} }

View File

@ -1,11 +1,12 @@
import { Hub } from "./hub"; import { TachoMotor } from "./tachomotor";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { TachoMotor } from "./tachomotor";
export class TechnicXLargeLinearMotor extends TachoMotor { export class TechnicXLargeLinearMotor extends TachoMotor {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.TECHNIC_XLARGE_LINEAR_MOTOR); super(hub, portId, Consts.DeviceType.TECHNIC_XLARGE_LINEAR_MOTOR);
} }

View File

@ -1,11 +1,12 @@
import { Device } from "./device"; import { Device } from "./device";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
export class TiltSensor extends Device { export class TiltSensor extends Device {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.TILT_SENSOR); super(hub, portId, Consts.DeviceType.TILT_SENSOR);
this.on("newListener", (event) => { this.on("newListener", (event) => {
@ -21,11 +22,12 @@ export class TiltSensor extends Device {
public receive (message: Buffer) { public receive (message: Buffer) {
const mode = this._mode; const mode = this._mode;
const isWeDo2 = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB);
switch (mode) { switch (mode) {
case 0x00: case 0x00:
const tiltX = message.readInt8(4); const tiltX = message.readInt8(isWeDo2 ? 2 : 4);
const tiltY = message.readInt8(5); const tiltY = message.readInt8(isWeDo2 ? 3 : 5);
/** /**
* Emits when a tilt sensor is activated. * Emits when a tilt sensor is activated.
* @event LPF2Hub#tilt * @event LPF2Hub#tilt

View File

@ -1,11 +1,12 @@
import { BasicMotor } from "./basicmotor"; import { BasicMotor } from "./basicmotor";
import { Hub } from "./hub";
import { IDeviceInterface } from "./interfaces";
import * as Consts from "./consts"; import * as Consts from "./consts";
export class TrainMotor extends BasicMotor { export class TrainMotor extends BasicMotor {
constructor (hub: Hub, portId: number) { constructor (hub: IDeviceInterface, portId: number) {
super(hub, portId, Consts.DeviceType.TRAIN_MOTOR); super(hub, portId, Consts.DeviceType.TRAIN_MOTOR);
} }

View File

@ -2,18 +2,8 @@ import { Peripheral } from "@abandonware/noble";
import { IBLEAbstraction } from "./interfaces"; import { IBLEAbstraction } from "./interfaces";
import { Device } from "./device";
import { Hub } from "./hub"; import { Hub } from "./hub";
import { ColorDistanceSensor } from "./colordistancesensor";
import { Light } from "./light";
import { MediumLinearMotor } from "./mediumlinearmotor";
import { MoveHubMediumLinearMotor } from "./movehubmediumlinearmotor";
import { SimpleMediumLinearMotor } from "./simplemediumlinearmotor";
import { TechnicLargeLinearMotor } from "./techniclargelinearmotor";
import { TechnicXLargeLinearMotor } from "./technicxlargelinearmotor";
import { TrainMotor } from "./trainmotor";
import * as Consts from "./consts"; import * as Consts from "./consts";
import { isWebBluetooth } from "./utils"; import { isWebBluetooth } from "./utils";
@ -67,8 +57,8 @@ export class WeDo2SmartHub extends Hub {
await this._bleDevice.discoverCharacteristicsForService("battery_service"); await this._bleDevice.discoverCharacteristicsForService("battery_service");
await this._bleDevice.discoverCharacteristicsForService("device_information"); await this._bleDevice.discoverCharacteristicsForService("device_information");
} }
this._activatePortDevice(0x03, 0x15, 0x00, 0x00); // Activate voltage reports this.subscribe(0x03, 0x15, 0x00); // Activate voltage reports
this._activatePortDevice(0x04, 0x14, 0x00, 0x00); // Activate current reports this.subscribe(0x04, 0x14, 0x00); // Activate current reports
debug("Connect completed"); debug("Connect completed");
this.emit("connect"); this.emit("connect");
resolve(); resolve();
@ -230,8 +220,8 @@ export class WeDo2SmartHub extends Hub {
} }
protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { public subscribe (portId: number, deviceType: number, mode: number) {
this.send(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, callback); this.send(Buffer.from([0x01, 0x02, portId, deviceType, mode, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE);
} }
@ -277,47 +267,43 @@ export class WeDo2SmartHub extends Hub {
const deviceType = event ? data[3] : 0; const deviceType = event ? data[3] : 0;
if (event === 0x01) { if (event === 0x01) {
const device = this._createDevice(deviceType, portId);
let device;
switch (deviceType) {
case Consts.DeviceType.LIGHT:
device = new Light(this, portId);
break;
// case Consts.DeviceType.BOOST_TACHO_MOTOR:
// device = new BoostTachoMotor(this, portId);
// break;
// case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR:
// device = new ControlPlusLargeMotor(this, portId);
// break;
// case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR:
// device = new ControlPlusXLargeMotor(this, portId);
// break;
case Consts.DeviceType.COLOR_DISTANCE_SENSOR:
device = new ColorDistanceSensor(this, portId);
break;
default:
device = new Device(this, portId, deviceType);
break;
}
this._attachDevice(device); this._attachDevice(device);
} else if (event === 0x00) {
const device = this._getDeviceByPortId(portId);
if (device) {
this._detachDevice(device);
}
} }
} }
private _parseSensorMessage (message: Buffer) { private _parseSensorMessage (message: Buffer) {
debug("Received Message (WEDO2_SENSOR_VALUE)", message);
if (message[0] === 0x01) {
/**
* Emits when a button is pressed.
* @event WeDo2SmartHub#button
* @param {string} button
* @param {ButtonState} state
*/
this.emit("button", "GREEN", Consts.ButtonState.PRESSED);
return;
} else if (message[0] === 0x00) {
this.emit("button", "GREEN", Consts.ButtonState.RELEASED);
return;
}
const portId = message[1]; const portId = message[1];
const device = this._getDeviceByPortId(portId); const device = this._getDeviceByPortId(portId);
if (device) { if (device) {
console.log(portId, device.type);
device.receive(message); device.receive(message);
} }
// debug("Received Message (WEDO2_SENSOR_VALUE)", data);
// if (data[0] === 0x01) { // if (data[0] === 0x01) {
// /** // /**
// * Emits when a button is pressed. // * Emits when a button is pressed.
@ -350,20 +336,6 @@ export class WeDo2SmartHub extends Hub {
// if (port && port.connected) { // if (port && port.connected) {
// switch (port.type) { // switch (port.type) {
// case Consts.DeviceType.WEDO2_DISTANCE: {
// let distance = data[2];
// if (data[3] === 1) {
// distance = data[2] + 255;
// }
// /**
// * Emits when a distance sensor is activated.
// * @event WeDo2SmartHub#distance
// * @param {string} port
// * @param {number} distance Distance, in millimeters.
// */
// this.emit("distance", port.id, distance * 10);
// break;
// }
// case Consts.DeviceType.COLOR_DISTANCE_SENSOR: { // case Consts.DeviceType.COLOR_DISTANCE_SENSOR: {
// const distance = data[2]; // const distance = data[2];
// /** // /**
@ -375,40 +347,6 @@ export class WeDo2SmartHub extends Hub {
// this.emit("color", port.id, distance); // this.emit("color", port.id, distance);
// break; // break;
// } // }
// case Consts.DeviceType.WEDO2_TILT: {
// this._lastTiltX = data.readInt8(2);
// this._lastTiltY = data.readInt8(3);
// /**
// * Emits when a tilt sensor is activated.
// * @event WeDo2SmartHub#tilt
// * @param {string} port
// * @param {number} x
// * @param {number} y
// */
// this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY);
// break;
// }
// case Consts.DeviceType.BOOST_TACHO_MOTOR: {
// const rotation = data.readInt32LE(2);
// /**
// * Emits when a rotation sensor is activated.
// * @event WeDo2SmartHub#rotate
// * @param {string} port
// * @param {number} rotation
// */
// this.emit("rotate", port.id, rotation);
// break;
// }
// case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: {
// const rotation = data.readInt32LE(2);
// this.emit("rotate", port.id, rotation);
// break;
// }
// case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR: {
// const rotation = data.readInt32LE(2);
// this.emit("rotate", port.id, rotation);
// break;
// }
// } // }
// } // }