Added autosubscribe when adding eventlisteners
This commit is contained in:
parent
d453fe52fb
commit
4af1d3d69b
43
examples/new_device_test.js
Normal file
43
examples/new_device_test.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* This demonstrates connecting multiple hubs to your laptop. Once connected, all the hubs LED lights will cycle through the same colors simultaneously.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const PoweredUP = require("..");
|
||||||
|
|
||||||
|
const poweredUP = new PoweredUP.PoweredUP();
|
||||||
|
poweredUP.scan(); // Start scanning for hubs
|
||||||
|
|
||||||
|
console.log("Looking for Hubs...");
|
||||||
|
|
||||||
|
poweredUP.on("discover", async (hub) => { // Wait to discover hubs
|
||||||
|
|
||||||
|
await hub.connect(); // Connect to hub
|
||||||
|
console.log(`Connected to ${hub.name}!`);
|
||||||
|
|
||||||
|
hub.on("attach", (device) => {
|
||||||
|
|
||||||
|
if (device instanceof PoweredUP.ControlPlusLargeMotor) {
|
||||||
|
const motor = device;
|
||||||
|
motor.setSpeed(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device instanceof PoweredUP.ColorDistanceSensor) {
|
||||||
|
const sensor = device;
|
||||||
|
sensor.on("distance", (distance) => { // Adding an event handler for distance automatically subscribes to distance notifications
|
||||||
|
console.log(`Distance ${distance}`);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
device.on("detach", () => {
|
||||||
|
console.log(device.connected);
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
hub.on("disconnect", () => {
|
||||||
|
console.log("Hub disconnected");
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
@ -3,6 +3,8 @@ import { Hub } from "./hub";
|
|||||||
|
|
||||||
import * as Consts from "./consts";
|
import * as Consts from "./consts";
|
||||||
|
|
||||||
|
import { mapSpeed } from "./utils";
|
||||||
|
|
||||||
export class BasicMotor extends Device {
|
export class BasicMotor extends Device {
|
||||||
|
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ export class BasicMotor extends Device {
|
|||||||
*/
|
*/
|
||||||
public setSpeed (speed: number) {
|
public setSpeed (speed: number) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const data = Buffer.from([0x81, this.portId, 0x11, 0x51, 0x00, speed]);
|
const data = Buffer.from([0x81, this.portId, 0x11, 0x51, 0x00, mapSpeed(speed)]);
|
||||||
this.send(data);
|
this.send(data);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
|
@ -36,17 +36,14 @@ export class BoostMoveHub extends LPF2Hub {
|
|||||||
|
|
||||||
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
||||||
super(device, autoSubscribe);
|
super(device, autoSubscribe);
|
||||||
this.type = Consts.HubType.BOOST_MOVE_HUB;
|
this._type = Consts.HubType.BOOST_MOVE_HUB;
|
||||||
this._ports = {
|
this._portNames = {
|
||||||
"A": new Port("A", 0),
|
"A": 0,
|
||||||
"B": new Port("B", 1),
|
"B": 1,
|
||||||
"C": new Port("C", 2),
|
"C": 2,
|
||||||
"D": new Port("D", 3),
|
"D": 3,
|
||||||
"TILT": new Port("TILT", 58)
|
"TILT": 58
|
||||||
};
|
};
|
||||||
this.on("attach", (port, type) => {
|
|
||||||
this._combinePorts(port, type);
|
|
||||||
});
|
|
||||||
debug("Discovered Boost Move Hub");
|
debug("Discovered Boost Move Hub");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,253 +58,253 @@ export class BoostMoveHub extends LPF2Hub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Set the motor speed on a given port.
|
// * Set the motor speed on a given port.
|
||||||
* @method BoostMoveHub#setMotorSpeed
|
// * @method BoostMoveHub#setMotorSpeed
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number | Array.<number>} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
// * @param {number | Array.<number>} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
||||||
* @param {number} [time] How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely.
|
// * @param {number} [time] How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely.
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
// * @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
||||||
*/
|
// */
|
||||||
public setMotorSpeed (port: string, speed: number | [number, number], time?: number | boolean) {
|
// public setMotorSpeed (port: string, speed: number | [number, number], time?: number | boolean) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
// if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
||||||
throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
// throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
||||||
}
|
// }
|
||||||
let cancelEventTimer = true;
|
// let cancelEventTimer = true;
|
||||||
if (typeof time === "boolean") {
|
// if (typeof time === "boolean") {
|
||||||
if (time === true) {
|
// if (time === true) {
|
||||||
cancelEventTimer = false;
|
// cancelEventTimer = false;
|
||||||
}
|
// }
|
||||||
time = undefined;
|
// time = undefined;
|
||||||
}
|
// }
|
||||||
if (cancelEventTimer) {
|
// if (cancelEventTimer) {
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
}
|
// }
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
if (time && typeof time === "number") {
|
// if (time && typeof time === "number") {
|
||||||
|
|
||||||
if (
|
// if (
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
) {
|
// ) {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0a, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0a, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @ts-ignore: The type of speed is properly checked at the start
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
}
|
// }
|
||||||
data.writeUInt16LE(time > 65535 ? 65535 : time, 4);
|
// data.writeUInt16LE(time > 65535 ? 65535 : time, 4);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @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)]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
const timeout = global.setTimeout(() => {
|
// const timeout = global.setTimeout(() => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
// return resolve();
|
||||||
// @ts-ignore: The type of time is properly checked at the start
|
// // @ts-ignore: The type of time is properly checked at the start
|
||||||
}, time);
|
// }, time);
|
||||||
portObj.setEventTimer(timeout);
|
// portObj.setEventTimer(timeout);
|
||||||
}
|
// }
|
||||||
|
|
||||||
} else {
|
// } else {
|
||||||
|
|
||||||
if (
|
// if (
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
) {
|
// ) {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x02, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x02, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @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]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
}
|
// }
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @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)]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Ramp the motor speed on a given port.
|
// * Ramp the motor speed on a given port.
|
||||||
* @method BoostMoveHub#rampMotorSpeed
|
// * @method BoostMoveHub#rampMotorSpeed
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} time How long the ramp should last (in milliseconds).
|
// * @param {number} time How long the ramp should last (in milliseconds).
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
// * @returns {Promise} Resolved upon successful completion of command.
|
||||||
*/
|
// */
|
||||||
public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
// public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
// this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
||||||
.on("changeSpeed", (speed) => {
|
// .on("changeSpeed", (speed) => {
|
||||||
this.setMotorSpeed(port, speed, true);
|
// this.setMotorSpeed(port, speed, true);
|
||||||
})
|
// })
|
||||||
.on("finished", resolve);
|
// .on("finished", resolve);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Rotate a motor by a given angle.
|
// * Rotate a motor by a given angle.
|
||||||
* @method BoostMoveHub#setMotorAngle
|
// * @method BoostMoveHub#setMotorAngle
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} angle How much the motor should be rotated (in degrees).
|
// * @param {number} angle How much the motor should be rotated (in degrees).
|
||||||
* @param {number | Array.<number>} [speed=100] For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
// * @param {number | Array.<number>} [speed=100] For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
||||||
* @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 setMotorAngle (port: string, angle: number, speed: number | [number, number] = 100) {
|
// public setMotorAngle (port: string, angle: number, speed: number | [number, number] = 100) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!(
|
// if (!(
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
)) {
|
// )) {
|
||||||
throw new Error("Angle rotation is only available when using a Boost Tacho Motor, Boost Move Hub Motor, Control+ Medium Motor, or Control+ Large Motor");
|
// throw new Error("Angle rotation is only available when using a Boost Tacho Motor, Boost Move Hub Motor, Control+ Medium Motor, or Control+ Large Motor");
|
||||||
}
|
// }
|
||||||
if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
// if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
||||||
throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
// throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
||||||
}
|
// }
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0c, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0c, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @ts-ignore: The type of speed is properly checked at the start
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
}
|
// }
|
||||||
data.writeUInt32LE(angle, 4);
|
// data.writeUInt32LE(angle, 4);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Tell motor to goto an absolute position
|
// * Tell motor to goto an absolute position
|
||||||
* @method BoostMoveHub#setAbsolutePosition
|
// * @method BoostMoveHub#setAbsolutePosition
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} pos The position of the motor to go to
|
// * @param {number} pos The position of the motor to go to
|
||||||
* @param {number | Array.<number>} [speed=100] A value between 1 - 100 should be set (Direction does not apply when going to absolute position)
|
// * @param {number | Array.<number>} [speed=100] A value between 1 - 100 should be set (Direction does not apply when going to absolute position)
|
||||||
* @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 setAbsolutePosition (port: string, pos: number, speed: number = 100) {
|
// public setAbsolutePosition (port: string, pos: number, speed: number = 100) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!(
|
// if (!(
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
)) {
|
// )) {
|
||||||
throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
// throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
||||||
}
|
// }
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
data.writeInt32LE(pos, 4);
|
// data.writeInt32LE(pos, 4);
|
||||||
data.writeInt32LE(pos, 8);
|
// data.writeInt32LE(pos, 8);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @ts-ignore: The type of speed is properly checked at the start
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
data.writeInt32LE(pos, 4);
|
// data.writeInt32LE(pos, 4);
|
||||||
}
|
// }
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Reset the current motor position as absolute position zero
|
// * Reset the current motor position as absolute position zero
|
||||||
* @method BoostMoveHub#resetAbsolutePosition
|
// * @method BoostMoveHub#resetAbsolutePosition
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @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 resetAbsolutePosition (port: string) {
|
// public resetAbsolutePosition (port: string) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!(
|
// if (!(
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
)) {
|
// )) {
|
||||||
throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
// throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
||||||
}
|
// }
|
||||||
return new Promise((resolve) => {
|
// return new Promise((resolve) => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
// return resolve();
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Fully (hard) stop the motor on a given port.
|
// * Fully (hard) stop the motor on a given port.
|
||||||
* @method BoostMoveHub#brakeMotor
|
// * @method BoostMoveHub#brakeMotor
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
// * @returns {Promise} Resolved upon successful completion of command.
|
||||||
*/
|
// */
|
||||||
public brakeMotor (port: string) {
|
// public brakeMotor (port: string) {
|
||||||
return this.setMotorSpeed(port, 127);
|
// return this.setMotorSpeed(port, 127);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Set the light brightness on a given port.
|
// * Set the light brightness on a given port.
|
||||||
* @method BoostMoveHub#setLightBrightness
|
// * @method BoostMoveHub#setLightBrightness
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} brightness Brightness value between 0-100 (0 is off)
|
// * @param {number} brightness Brightness value between 0-100 (0 is off)
|
||||||
* @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
// * @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
// * @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
||||||
*/
|
// */
|
||||||
public setLightBrightness (port: string, brightness: number, time?: number) {
|
// public setLightBrightness (port: string, brightness: number, time?: number) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
if (time) {
|
// if (time) {
|
||||||
const timeout = global.setTimeout(() => {
|
// const timeout = global.setTimeout(() => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
// return resolve();
|
||||||
}, time);
|
// }, time);
|
||||||
portObj.setEventTimer(timeout);
|
// portObj.setEventTimer(timeout);
|
||||||
} else {
|
// } else {
|
||||||
return resolve();
|
// return resolve();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
protected _checkFirmware (version: string) {
|
protected _checkFirmware (version: string) {
|
||||||
|
@ -7,6 +7,19 @@ export class ColorDistanceSensor extends Device {
|
|||||||
|
|
||||||
constructor (hub: Hub, portId: number) {
|
constructor (hub: Hub, portId: number) {
|
||||||
super(hub, portId, Consts.DeviceType.COLOR_DISTANCE_SENSOR);
|
super(hub, portId, Consts.DeviceType.COLOR_DISTANCE_SENSOR);
|
||||||
|
|
||||||
|
this.on("newListener", (event) => {
|
||||||
|
switch (event) {
|
||||||
|
case "color":
|
||||||
|
this.subscribe(0x00);
|
||||||
|
break;
|
||||||
|
case "distance":
|
||||||
|
this.subscribe(0x01);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,19 +38,19 @@ export class ControlPlusHub extends LPF2Hub {
|
|||||||
|
|
||||||
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
||||||
super(device, autoSubscribe);
|
super(device, autoSubscribe);
|
||||||
this.type = Consts.HubType.CONTROL_PLUS_HUB;
|
this._type = Consts.HubType.CONTROL_PLUS_HUB;
|
||||||
this._ports = {
|
this._portNames = {
|
||||||
"A": new Port("A", 0),
|
"A": 0,
|
||||||
"B": new Port("B", 1),
|
"B": 1,
|
||||||
"C": new Port("C", 2),
|
"C": 2,
|
||||||
"D": new Port("D", 3),
|
"D": 3,
|
||||||
"ACCEL": new Port("ACCEL", 97),
|
"ACCEL": 97,
|
||||||
"GYRO": new Port("GYRO", 98),
|
"GYRO": 98,
|
||||||
"TILT": new Port("TILT", 99)
|
"TILT": 99
|
||||||
};
|
};
|
||||||
this.on("attach", (port, type) => {
|
// // this.on("attach", (port, type) => {
|
||||||
this._combinePorts(port, type);
|
// // this._combinePorts(port, type);
|
||||||
});
|
// // });
|
||||||
debug("Discovered Control+ Hub");
|
debug("Discovered Control+ Hub");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ export class ControlPlusHub extends LPF2Hub {
|
|||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
debug("Connecting to Control+ Hub");
|
debug("Connecting to Control+ Hub");
|
||||||
await super.connect();
|
await super.connect();
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x3d, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01])); // Temperature
|
this.send(Buffer.from([0x41, 0x3d, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL); // Temperature
|
||||||
debug("Connect completed");
|
debug("Connect completed");
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
@ -75,200 +75,200 @@ export class ControlPlusHub extends LPF2Hub {
|
|||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
||||||
*/
|
*/
|
||||||
public setMotorSpeed (port: string, speed: number | [number, number], time?: number | boolean) {
|
public setMotorSpeed (port: string, speed: number | [number, number], time?: number | boolean) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
// if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
||||||
throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
// throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
||||||
}
|
// }
|
||||||
let cancelEventTimer = true;
|
// let cancelEventTimer = true;
|
||||||
if (typeof time === "boolean") {
|
// if (typeof time === "boolean") {
|
||||||
if (time === true) {
|
// if (time === true) {
|
||||||
cancelEventTimer = false;
|
// cancelEventTimer = false;
|
||||||
}
|
// }
|
||||||
time = undefined;
|
// time = undefined;
|
||||||
}
|
// }
|
||||||
if (cancelEventTimer) {
|
// if (cancelEventTimer) {
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
}
|
// }
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
if (time && typeof time === "number") {
|
// if (time && typeof time === "number") {
|
||||||
|
|
||||||
if (
|
// if (
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
) {
|
// ) {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0a, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0a, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @ts-ignore: The type of speed is properly checked at the start
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
}
|
// }
|
||||||
data.writeUInt16LE(time > 65535 ? 65535 : time, 4);
|
// data.writeUInt16LE(time > 65535 ? 65535 : time, 4);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @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)]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
const timeout = global.setTimeout(() => {
|
// const timeout = global.setTimeout(() => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
// return resolve();
|
||||||
// @ts-ignore: The type of time is properly checked at the start
|
// // @ts-ignore: The type of time is properly checked at the start
|
||||||
}, time);
|
// }, time);
|
||||||
portObj.setEventTimer(timeout);
|
// portObj.setEventTimer(timeout);
|
||||||
}
|
// }
|
||||||
|
|
||||||
} else {
|
// } else {
|
||||||
|
|
||||||
if (portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR || portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR) {
|
// if (portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR || portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR) {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x02, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x02, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @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]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x01, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
}
|
// }
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @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)]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Ramp the motor speed on a given port.
|
// * Ramp the motor speed on a given port.
|
||||||
* @method ControlPlusHub#rampMotorSpeed
|
// * @method ControlPlusHub#rampMotorSpeed
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} time How long the ramp should last (in milliseconds).
|
// * @param {number} time How long the ramp should last (in milliseconds).
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
// * @returns {Promise} Resolved upon successful completion of command.
|
||||||
*/
|
// */
|
||||||
public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
// public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
// this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
||||||
.on("changeSpeed", (speed) => {
|
// .on("changeSpeed", (speed) => {
|
||||||
this.setMotorSpeed(port, speed, true);
|
// this.setMotorSpeed(port, speed, true);
|
||||||
})
|
// })
|
||||||
.on("finished", resolve);
|
// .on("finished", resolve);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Rotate a motor by a given angle.
|
// * Rotate a motor by a given angle.
|
||||||
* @method ControlPlusHub#setMotorAngle
|
// * @method ControlPlusHub#setMotorAngle
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} angle How much the motor should be rotated (in degrees).
|
// * @param {number} angle How much the motor should be rotated (in degrees).
|
||||||
* @param {number | Array.<number>} [speed=100] For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
// * @param {number | Array.<number>} [speed=100] For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
||||||
* @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 setMotorAngle (port: string, angle: number, speed: number | [number, number] = 100) {
|
// public setMotorAngle (port: string, angle: number, speed: number | [number, number] = 100) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!(
|
// if (!(
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
// portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
)) {
|
// )) {
|
||||||
throw new Error("Angle rotation is only available when using a Boost Tacho Motor, Boost Move Hub Motor, Control+ Medium Motor, or Control+ Large Motor");
|
// throw new Error("Angle rotation is only available when using a Boost Tacho Motor, Boost Move Hub Motor, Control+ Medium Motor, or Control+ Large Motor");
|
||||||
}
|
// }
|
||||||
if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
// if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
||||||
throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
// throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
||||||
}
|
// }
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0c, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0c, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @ts-ignore: The type of speed is properly checked at the start
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
}
|
// }
|
||||||
data.writeUInt32LE(angle, 4);
|
// data.writeUInt32LE(angle, 4);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Tell motor to goto an absolute position
|
// * Tell motor to goto an absolute position
|
||||||
* @method ControlPlusHub#setAbsolutePosition
|
// * @method ControlPlusHub#setAbsolutePosition
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} pos The position of the motor to go to
|
// * @param {number} pos The position of the motor to go to
|
||||||
* @param {number | Array.<number>} [speed=100] A value between 1 - 100 should be set (Direction does not apply when going to absolute position)
|
// * @param {number | Array.<number>} [speed=100] A value between 1 - 100 should be set (Direction does not apply when going to absolute position)
|
||||||
* @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 setAbsolutePosition (port: string, pos: number, speed: number = 100) {
|
// public setAbsolutePosition (port: string, pos: number, speed: number = 100) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!(
|
// if (!(
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
)) {
|
// )) {
|
||||||
throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
// throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
||||||
}
|
// }
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
portObj.busy = true;
|
// portObj.busy = true;
|
||||||
let data = null;
|
// let data = null;
|
||||||
if (this._virtualPorts[portObj.id]) {
|
// if (this._virtualPorts[portObj.id]) {
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
data.writeInt32LE(pos, 4);
|
// data.writeInt32LE(pos, 4);
|
||||||
data.writeInt32LE(pos, 8);
|
// data.writeInt32LE(pos, 8);
|
||||||
} else {
|
// } else {
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
// // @ts-ignore: The type of speed is properly checked at the start
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
// data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
||||||
data.writeInt32LE(pos, 4);
|
// data.writeInt32LE(pos, 4);
|
||||||
}
|
// }
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
portObj.finished = () => {
|
// portObj.finished = () => {
|
||||||
return resolve();
|
// return resolve();
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Reset the current motor position as absolute position zero
|
// * Reset the current motor position as absolute position zero
|
||||||
* @method ControlPlusHub#resetAbsolutePosition
|
// * @method ControlPlusHub#resetAbsolutePosition
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @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 resetAbsolutePosition (port: string) {
|
// public resetAbsolutePosition (port: string) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (!(
|
// if (!(
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
// portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
||||||
)) {
|
// )) {
|
||||||
throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
// throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
||||||
}
|
// }
|
||||||
return new Promise((resolve) => {
|
// return new Promise((resolve) => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
// return resolve();
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,32 +282,32 @@ export class ControlPlusHub extends LPF2Hub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Set the light brightness on a given port.
|
// * Set the light brightness on a given port.
|
||||||
* @method ControlPlusHub#setLightBrightness
|
// * @method ControlPlusHub#setLightBrightness
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} brightness Brightness value between 0-100 (0 is off)
|
// * @param {number} brightness Brightness value between 0-100 (0 is off)
|
||||||
* @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
// * @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
// * @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
||||||
*/
|
// */
|
||||||
public setLightBrightness (port: string, brightness: number, time?: number) {
|
// public setLightBrightness (port: string, brightness: number, time?: number) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
if (time) {
|
// if (time) {
|
||||||
const timeout = global.setTimeout(() => {
|
// const timeout = global.setTimeout(() => {
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
// const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
// this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
// return resolve();
|
||||||
}, time);
|
// }, time);
|
||||||
portObj.setEventTimer(timeout);
|
// portObj.setEventTimer(timeout);
|
||||||
} else {
|
// } else {
|
||||||
return resolve();
|
// return resolve();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,20 @@ export class Device extends EventEmitter {
|
|||||||
private _portId: number;
|
private _portId: number;
|
||||||
private _connected: boolean = true;
|
private _connected: boolean = true;
|
||||||
private _type: number;
|
private _type: number;
|
||||||
|
private _busy: boolean = false;
|
||||||
|
private _finished: (() => void) | null = null;
|
||||||
|
|
||||||
constructor (hub: Hub, portId: number, type: number = Consts.DeviceType.UNKNOWN) {
|
constructor (hub: Hub, portId: number, type: number = Consts.DeviceType.UNKNOWN) {
|
||||||
super();
|
super();
|
||||||
this._hub = hub;
|
this._hub = hub;
|
||||||
this._portId = portId;
|
this._portId = portId;
|
||||||
this._type = type;
|
this._type = type;
|
||||||
console.log(`New device on ${this._portId} - ${this._type}`);
|
this.hub.on("detach", (device) => {
|
||||||
|
if (device.portId === this.portId) {
|
||||||
|
this._connected = false;
|
||||||
|
this.emit("detach");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public get connected () {
|
public get connected () {
|
||||||
@ -31,7 +38,7 @@ export class Device extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get port () {
|
public get port () {
|
||||||
return "A"; // TODO NK: Look up the port name from the relevant hub
|
return this.hub.getPortNameForPortId(this.portId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get type () {
|
public get type () {
|
||||||
@ -39,7 +46,11 @@ export class Device extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public send (data: Buffer, characteristic: string = Consts.BLECharacteristic.LPF2_ALL, callback?: () => void) {
|
public send (data: Buffer, characteristic: string = Consts.BLECharacteristic.LPF2_ALL, callback?: () => void) {
|
||||||
this.hub.send(characteristic, data, callback);
|
this.hub.send(data, characteristic, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscribe (mode: number) {
|
||||||
|
this.send(Buffer.from([0x41, this.portId, mode, 0x01, 0x00, 0x00, 0x00, 0x01]));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,11 @@ export class DuploTrainBase extends LPF2Hub {
|
|||||||
|
|
||||||
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
||||||
super(device, autoSubscribe);
|
super(device, autoSubscribe);
|
||||||
this.type = Consts.HubType.DUPLO_TRAIN_HUB;
|
this._type = Consts.HubType.DUPLO_TRAIN_HUB;
|
||||||
this._ports = {
|
this._portNames = {
|
||||||
"MOTOR": new Port("MOTOR", 0),
|
"MOTOR": 0,
|
||||||
"COLOR": new Port("COLOR", 18),
|
"COLOR": 18,
|
||||||
"SPEEDOMETER": new Port("SPEEDOMETER", 19)
|
"SPEEDOMETER": 19
|
||||||
};
|
};
|
||||||
debug("Discovered Duplo Train Base");
|
debug("Discovered Duplo Train Base");
|
||||||
}
|
}
|
||||||
@ -57,77 +57,6 @@ export class DuploTrainBase extends LPF2Hub {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the motor speed on a given port.
|
|
||||||
* @method DuploTrainBase#setMotorSpeed
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number | Array.<number>} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
|
||||||
* @param {number} [time] How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely.
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
|
||||||
*/
|
|
||||||
public setMotorSpeed (port: string, speed: number, time?: number | boolean) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
let cancelEventTimer = true;
|
|
||||||
if (typeof time === "boolean") {
|
|
||||||
if (time === true) {
|
|
||||||
cancelEventTimer = false;
|
|
||||||
}
|
|
||||||
time = undefined;
|
|
||||||
}
|
|
||||||
if (cancelEventTimer) {
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (time && typeof time === "number") {
|
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, this._mapSpeed(speed)]);
|
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
const timeout = global.setTimeout(() => {
|
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
|
||||||
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.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ramp the motor speed on a given port.
|
|
||||||
* @method DuploTrainBase#rampMotorSpeed
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
|
||||||
* @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
|
||||||
* @param {number} time How long the ramp should last (in milliseconds).
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
|
||||||
*/
|
|
||||||
public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
|
||||||
.on("changeSpeed", (speed) => {
|
|
||||||
this.setMotorSpeed(port, speed, true);
|
|
||||||
})
|
|
||||||
.on("finished", resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fully (hard) stop the motor on a given port.
|
|
||||||
* @method DuploTrainBase#brakeMotor
|
|
||||||
* @param {string} port
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
|
||||||
*/
|
|
||||||
public brakeMotor (port: string) {
|
|
||||||
return this.setMotorSpeed(port, 127);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a built-in train sound.
|
* Play a built-in train sound.
|
||||||
@ -138,7 +67,7 @@ export class DuploTrainBase extends LPF2Hub {
|
|||||||
public playSound (sound: number) {
|
public playSound (sound: number) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const data = Buffer.from([0x81, 0x01, 0x11, 0x51, 0x01, sound]);
|
const data = Buffer.from([0x81, 0x01, 0x11, 0x51, 0x01, sound]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
346
src/hub.ts
346
src/hub.ts
@ -19,12 +19,12 @@ export class Hub extends EventEmitter {
|
|||||||
|
|
||||||
public autoSubscribe: boolean = true;
|
public autoSubscribe: boolean = true;
|
||||||
public useSpeedMap: boolean = true;
|
public useSpeedMap: boolean = true;
|
||||||
public type: Consts.HubType = Consts.HubType.UNKNOWN;
|
protected _type: Consts.HubType = Consts.HubType.UNKNOWN;
|
||||||
|
|
||||||
protected _attachedDevices: Device[] = [];
|
protected _attachedDevices: Device[] = [];
|
||||||
|
|
||||||
protected _ports: {[port: string]: Port} = {};
|
protected _portNames: {[port: string]: number} = {};
|
||||||
protected _virtualPorts: {[port: string]: Port} = {};
|
// protected _virtualPorts: {[port: string]: Port} = {};
|
||||||
|
|
||||||
protected _name: string = "";
|
protected _name: string = "";
|
||||||
protected _firmwareVersion: string = "0.0.00.0000";
|
protected _firmwareVersion: string = "0.0.00.0000";
|
||||||
@ -63,6 +63,15 @@ export class Hub extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @property {string} type Hub type
|
||||||
|
*/
|
||||||
|
public get type () {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @readonly
|
* @readonly
|
||||||
* @property {string} firmwareVersion Firmware version of the hub
|
* @property {string} firmwareVersion Firmware version of the hub
|
||||||
@ -160,44 +169,55 @@ export class Hub extends EventEmitter {
|
|||||||
* @method Hub#disconnect
|
* @method Hub#disconnect
|
||||||
* @returns {Promise} Resolved upon successful disconnect.
|
* @returns {Promise} Resolved upon successful disconnect.
|
||||||
*/
|
*/
|
||||||
public async disconnect () {
|
public disconnect () {
|
||||||
this._bleDevice.disconnect();
|
return this._bleDevice.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public getPortNameForPortId (portId: number) {
|
||||||
* Subscribe to sensor notifications on a given port.
|
for (const port of Object.keys(this._portNames)) {
|
||||||
* @method Hub#subscribe
|
console.log(port);
|
||||||
* @param {string} port
|
if (this._portNames[port] === portId) {
|
||||||
* @param {number} [mode] The sensor mode to activate. If no mode is provided, the default for that sensor will be chosen.
|
return port;
|
||||||
* @returns {Promise} Resolved upon successful issuance of command.
|
|
||||||
*/
|
|
||||||
public subscribe (port: string, mode?: number) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let newMode = this._getModeForDeviceType(this._portLookup(port).type);
|
|
||||||
if (mode !== undefined) {
|
|
||||||
newMode = mode;
|
|
||||||
}
|
}
|
||||||
this._activatePortDevice(this._portLookup(port).value, this._portLookup(port).type, newMode, 0x00, () => {
|
}
|
||||||
return resolve();
|
return;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsubscribe to sensor notifications on a given port.
|
// /**
|
||||||
* @method Hub#unsubscribe
|
// * Subscribe to sensor notifications on a given port.
|
||||||
* @param {string} port
|
// * @method Hub#subscribe
|
||||||
* @returns {Promise} Resolved upon successful issuance of command.
|
// * @param {string} port
|
||||||
*/
|
// * @param {number} [mode] The sensor mode to activate. If no mode is provided, the default for that sensor will be chosen.
|
||||||
public unsubscribe (port: string) {
|
// * @returns {Promise} Resolved upon successful issuance of command.
|
||||||
return new Promise((resolve, reject) => {
|
// */
|
||||||
const mode = this._getModeForDeviceType(this._portLookup(port).type);
|
// public subscribe (port: string, mode?: number) {
|
||||||
this._deactivatePortDevice(this._portLookup(port).value, this._portLookup(port).type, mode, 0x00, () => {
|
// return new Promise((resolve, reject) => {
|
||||||
return resolve();
|
// let newMode = this._getModeForDeviceType(this._portLookup(port).type);
|
||||||
});
|
// if (mode !== undefined) {
|
||||||
});
|
// newMode = mode;
|
||||||
}
|
// }
|
||||||
|
// this._activatePortDevice(this._portLookup(port).value, this._portLookup(port).type, newMode, 0x00, () => {
|
||||||
|
// return resolve();
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Unsubscribe to sensor notifications on a given port.
|
||||||
|
// * @method Hub#unsubscribe
|
||||||
|
// * @param {string} port
|
||||||
|
// * @returns {Promise} Resolved upon successful issuance of command.
|
||||||
|
// */
|
||||||
|
// public unsubscribe (port: string) {
|
||||||
|
// return new Promise((resolve, reject) => {
|
||||||
|
// const mode = this._getModeForDeviceType(this._portLookup(port).type);
|
||||||
|
// this._deactivatePortDevice(this._portLookup(port).value, this._portLookup(port).type, mode, 0x00, () => {
|
||||||
|
// return resolve();
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,28 +248,18 @@ export class Hub extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Get the hub type.
|
// * Get the device type for a given port.
|
||||||
* @method Hub#getHubType
|
// * @method Hub#getPortDeviceType
|
||||||
* @returns {HubType}
|
// * @param {string} port
|
||||||
*/
|
// * @returns {DeviceType}
|
||||||
public getHubType () {
|
// */
|
||||||
return this.type;
|
// public getPortDeviceType (port: string) {
|
||||||
}
|
// return this._portLookup(port).type;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
public send (message: Buffer, uuid: string, callback?: () => void) {
|
||||||
* Get the device type for a given port.
|
|
||||||
* @method Hub#getPortDeviceType
|
|
||||||
* @param {string} port
|
|
||||||
* @returns {DeviceType}
|
|
||||||
*/
|
|
||||||
public getPortDeviceType (port: string) {
|
|
||||||
return this._portLookup(port).type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public send (uuid: string, message: Buffer, callback?: () => void) {
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@ -273,26 +283,12 @@ export class Hub extends EventEmitter {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) {
|
protected _attachDevice (device: Device) {
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const exists = this._getDeviceByPortId(device.portId);
|
||||||
protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) {
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected _registerDeviceAttachment (device: Device) {
|
|
||||||
|
|
||||||
const exists = this._attachedDevices.find((attachedDevice) => attachedDevice.portId === device.portId);
|
|
||||||
|
|
||||||
if (exists) {
|
if (exists) {
|
||||||
// TODO NK: Remove existing zombie device
|
this._attachedDevices.splice(this._attachedDevices.findIndex((attachedDevice) => attachedDevice.portId === device.portId), 1);
|
||||||
} else {
|
} else {
|
||||||
this._attachedDevices.push(device);
|
this._attachedDevices.push(device);
|
||||||
}
|
}
|
||||||
@ -333,110 +329,126 @@ export class Hub extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected _getPortForPortNumber (num: number) {
|
protected _detachDevice (device: Device) {
|
||||||
|
this._attachedDevices.splice(this._attachedDevices.findIndex((attachedDevice) => attachedDevice.portId === device.portId), 1);
|
||||||
for (const key of Object.keys(this._ports)) {
|
/**
|
||||||
if (this._ports[key].value === num) {
|
* Emits when a device is detached from the Hub.
|
||||||
return this._ports[key];
|
* @event Hub#attach
|
||||||
}
|
* @param {Device} device
|
||||||
}
|
*/
|
||||||
|
this.emit("detach", device);
|
||||||
for (const key of Object.keys(this._virtualPorts)) {
|
|
||||||
if (this._virtualPorts[key].value === num) {
|
|
||||||
return this._virtualPorts[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected _mapSpeed (speed: number) { // Speed range of -100 to 100 is supported unless speed mapping is turned off, in which case, you're on your own!
|
protected _getDeviceByPortId (portId: number) {
|
||||||
if (!this.useSpeedMap) {
|
return this._attachedDevices.find((attachedDevice) => attachedDevice.portId === portId);
|
||||||
return speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (speed === 127) {
|
|
||||||
return 127; // Hard stop
|
|
||||||
}
|
|
||||||
|
|
||||||
if (speed > 100) {
|
|
||||||
speed = 100;
|
|
||||||
} else if (speed < -100) {
|
|
||||||
speed = -100;
|
|
||||||
}
|
|
||||||
|
|
||||||
return speed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected _calculateRamp (fromSpeed: number, toSpeed: number, time: number, port: Port) {
|
// protected _getPortForPortNumber (num: number) {
|
||||||
const emitter = new EventEmitter();
|
|
||||||
const steps = Math.abs(toSpeed - fromSpeed);
|
// for (const key of Object.keys(this._ports)) {
|
||||||
let delay = time / steps;
|
// if (this._ports[key].value === num) {
|
||||||
let increment = 1;
|
// return this._ports[key];
|
||||||
if (delay < 50 && steps > 0) {
|
// }
|
||||||
increment = 50 / delay;
|
// }
|
||||||
delay = 50;
|
|
||||||
}
|
// for (const key of Object.keys(this._virtualPorts)) {
|
||||||
if (fromSpeed > toSpeed) {
|
// if (this._virtualPorts[key].value === num) {
|
||||||
increment = -increment;
|
// return this._virtualPorts[key];
|
||||||
}
|
// }
|
||||||
let i = 0;
|
// }
|
||||||
const interval = setInterval(() => {
|
|
||||||
let speed = Math.round(fromSpeed + (++i * increment));
|
// return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected _portLookup (portName: string) {
|
// protected _mapSpeed (speed: number) { // Speed range of -100 to 100 is supported unless speed mapping is turned off, in which case, you're on your own!
|
||||||
const portNameUpper = portName.toUpperCase();
|
// if (!this.useSpeedMap) {
|
||||||
const port = this._ports[portNameUpper] || this._virtualPorts[portNameUpper];
|
// return speed;
|
||||||
if (!port) {
|
// }
|
||||||
throw new Error(`Port ${portNameUpper} does not exist on this Hub type`);
|
|
||||||
}
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getModeForDeviceType (type: Consts.DeviceType) {
|
// if (speed === 127) {
|
||||||
switch (type) {
|
// return 127; // Hard stop
|
||||||
case Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR:
|
// }
|
||||||
return 0x02;
|
|
||||||
case Consts.DeviceType.TRAIN_MOTOR:
|
// if (speed > 100) {
|
||||||
return 0x02;
|
// speed = 100;
|
||||||
case Consts.DeviceType.BOOST_TACHO_MOTOR:
|
// } else if (speed < -100) {
|
||||||
return 0x02;
|
// speed = -100;
|
||||||
case Consts.DeviceType.BOOST_MOVE_HUB_MOTOR:
|
// }
|
||||||
return 0x02;
|
|
||||||
case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR:
|
// return speed;
|
||||||
return 0x02;
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR:
|
|
||||||
return 0x02;
|
|
||||||
case Consts.DeviceType.CONTROL_PLUS_TILT:
|
// protected _calculateRamp (fromSpeed: number, toSpeed: number, time: number, port: Port) {
|
||||||
return 0x00;
|
// const emitter = new EventEmitter();
|
||||||
case Consts.DeviceType.CONTROL_PLUS_ACCELEROMETER:
|
// const steps = Math.abs(toSpeed - fromSpeed);
|
||||||
return 0x00;
|
// let delay = time / steps;
|
||||||
case Consts.DeviceType.COLOR_DISTANCE_SENSOR:
|
// let increment = 1;
|
||||||
return (this.type === Consts.HubType.WEDO2_SMART_HUB ? 0x00 : 0x08);
|
// if (delay < 50 && steps > 0) {
|
||||||
case Consts.DeviceType.BOOST_TILT:
|
// increment = 50 / delay;
|
||||||
return 0x04;
|
// delay = 50;
|
||||||
default:
|
// }
|
||||||
return 0x00;
|
// 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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// protected _portLookup (portName: string) {
|
||||||
|
// const portNameUpper = portName.toUpperCase();
|
||||||
|
// const port = this._ports[portNameUpper] || this._virtualPorts[portNameUpper];
|
||||||
|
// if (!port) {
|
||||||
|
// throw new Error(`Port ${portNameUpper} does not exist on this Hub type`);
|
||||||
|
// }
|
||||||
|
// return port;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
511
src/lpf2hub.ts
511
src/lpf2hub.ts
@ -48,21 +48,21 @@ 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.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, this._voltagePort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate voltage reports
|
this.send(Buffer.from([0x41, this._voltagePort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL); // Activate voltage reports
|
||||||
}
|
}
|
||||||
if (this._currentPort !== undefined) {
|
if (this._currentPort !== undefined) {
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, this._currentPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01])); // Activate current reports
|
this.send(Buffer.from([0x41, this._currentPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL); // Activate current reports
|
||||||
}
|
}
|
||||||
if (this.type === Consts.HubType.DUPLO_TRAIN_HUB) {
|
if (this._type === Consts.HubType.DUPLO_TRAIN_HUB) {
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x41, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01]));
|
this.send(Buffer.from([0x41, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL);
|
||||||
}
|
}
|
||||||
await this.sleep(100);
|
await this.sleep(100);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x02, 0x02])); // Activate button reports
|
this.send(Buffer.from([0x01, 0x02, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate button reports
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x03, 0x05])); // Request firmware version
|
this.send(Buffer.from([0x01, 0x03, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request firmware version
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x04, 0x05])); // Request hardware version
|
this.send(Buffer.from([0x01, 0x04, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request hardware version
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x05, 0x02])); // Activate RSSI updates
|
this.send(Buffer.from([0x01, 0x05, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate RSSI updates
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x06, 0x02])); // Activate battery level reports
|
this.send(Buffer.from([0x01, 0x06, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate battery level reports
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x01, 0x0d, 0x05])); // Request primary MAC address
|
this.send(Buffer.from([0x01, 0x0d, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request primary MAC address
|
||||||
this.emit("connect");
|
this.emit("connect");
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -76,7 +76,7 @@ export class LPF2Hub extends Hub {
|
|||||||
*/
|
*/
|
||||||
public shutdown () {
|
public shutdown () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x02, 0x01]), () => {
|
this.send(Buffer.from([0x02, 0x01]), Consts.BLECharacteristic.LPF2_ALL, () => {
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -97,8 +97,8 @@ export class LPF2Hub extends Hub {
|
|||||||
let data = Buffer.from([0x01, 0x01, 0x01]);
|
let data = Buffer.from([0x01, 0x01, 0x01]);
|
||||||
data = Buffer.concat([data, Buffer.from(name, "ascii")]);
|
data = Buffer.concat([data, Buffer.from(name, "ascii")]);
|
||||||
// Send this twice, as sometimes the first time doesn't take
|
// Send this twice, as sometimes the first time doesn't take
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
this._name = name;
|
this._name = name;
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
@ -114,12 +114,12 @@ export class LPF2Hub extends Hub {
|
|||||||
public setLEDColor (color: number | boolean) {
|
public setLEDColor (color: number | boolean) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let data = Buffer.from([0x41, this._ledPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);
|
let data = Buffer.from([0x41, this._ledPort, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
if (typeof color === "boolean") {
|
if (typeof color === "boolean") {
|
||||||
color = 0;
|
color = 0;
|
||||||
}
|
}
|
||||||
data = Buffer.from([0x81, this._ledPort, 0x11, 0x51, 0x00, color]);
|
data = Buffer.from([0x81, this._ledPort, 0x11, 0x51, 0x00, color]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -136,9 +136,9 @@ export class LPF2Hub extends Hub {
|
|||||||
public setLEDRGB (red: number, green: number, blue: number) {
|
public setLEDRGB (red: number, green: number, blue: number) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let data = Buffer.from([0x41, this._ledPort, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00]);
|
let data = Buffer.from([0x41, this._ledPort, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
data = Buffer.from([0x81, this._ledPort, 0x11, 0x51, 0x01, red, green, blue]);
|
data = Buffer.from([0x81, this._ledPort, 0x11, 0x51, 0x01, red, green, blue]);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
this.send(data, Consts.BLECharacteristic.LPF2_ALL);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -146,14 +146,14 @@ export class LPF2Hub extends Hub {
|
|||||||
|
|
||||||
public sendRaw (message: Buffer) {
|
public sendRaw (message: Buffer) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, message, () => {
|
this.send(message, Consts.BLECharacteristic.LPF2_ALL, () => {
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public send (uuid: string, message: Buffer, callback?: () => void) {
|
public send (message: Buffer, uuid: string, callback?: () => void) {
|
||||||
message = Buffer.concat([Buffer.alloc(2), message]);
|
message = Buffer.concat([Buffer.alloc(2), message]);
|
||||||
message[0] = message.length;
|
message[0] = message.length;
|
||||||
debug("Sent Message (LPF2_ALL)", message);
|
debug("Sent Message (LPF2_ALL)", message);
|
||||||
@ -161,30 +161,30 @@ export class LPF2Hub extends Hub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) {
|
// 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);
|
// this.send(Buffer.from([0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), Consts.BLECharacteristic.LPF2_ALL, callback);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) {
|
// 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);
|
// this.send(Buffer.from([0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x00]), Consts.BLECharacteristic.LPF2_ALL, callback);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
protected _combinePorts (port: string, type: number) {
|
// protected _combinePorts (port: string, type: number) {
|
||||||
if (!this._ports[port]) {
|
// if (!this._ports[port]) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
if (portObj) {
|
// if (portObj) {
|
||||||
Object.keys(this._ports).forEach((id) => {
|
// 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}`]) {
|
// 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);
|
// debug("Combining ports", portObj.value < this._ports[id].value ? portObj.id : id, portObj.value > this._ports[id].value ? portObj.id : id);
|
||||||
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]));
|
// this.send(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]), Consts.BLECharacteristic.LPF2_ALL);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
protected _checkFirmware (version: string) {
|
protected _checkFirmware (version: string) {
|
||||||
@ -297,6 +297,7 @@ export class LPF2Hub extends Hub {
|
|||||||
const event = data[4];
|
const event = data[4];
|
||||||
const deviceType = event ? data.readUInt16LE(5) : 0;
|
const deviceType = event ? data.readUInt16LE(5) : 0;
|
||||||
|
|
||||||
|
// Handle device attachments
|
||||||
if (event === 0x01) {
|
if (event === 0x01) {
|
||||||
|
|
||||||
let device;
|
let device;
|
||||||
@ -313,8 +314,14 @@ export class LPF2Hub extends Hub {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._registerDeviceAttachment(device);
|
this._attachDevice(device);
|
||||||
|
|
||||||
|
// Handle device detachments
|
||||||
|
} else if (event === 0x00) {
|
||||||
|
const device = this._getDeviceByPortId(portId);
|
||||||
|
if (device) {
|
||||||
|
this._detachDevice(device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -358,8 +365,8 @@ export class LPF2Hub extends Hub {
|
|||||||
|
|
||||||
|
|
||||||
private _sendPortInformationRequest (port: number) {
|
private _sendPortInformationRequest (port: number) {
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x21, port, 0x01]));
|
this.send(Buffer.from([0x21, port, 0x01]), Consts.BLECharacteristic.LPF2_ALL);
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x21, port, 0x02])); // Mode combinations
|
this.send(Buffer.from([0x21, port, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Mode combinations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -390,7 +397,7 @@ export class LPF2Hub extends Hub {
|
|||||||
|
|
||||||
|
|
||||||
private _sendModeInformationRequest (port: number, mode: number, type: number) {
|
private _sendModeInformationRequest (port: number, mode: number, type: number) {
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, Buffer.from([0x22, port, mode, type]));
|
this.send(Buffer.from([0x22, port, mode, type]), Consts.BLECharacteristic.LPF2_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -426,233 +433,233 @@ export class LPF2Hub extends Hub {
|
|||||||
|
|
||||||
private _parsePortAction (data: Buffer) {
|
private _parsePortAction (data: Buffer) {
|
||||||
|
|
||||||
const port = this._getPortForPortNumber(data[3]);
|
// const port = this._getPortForPortNumber(data[3]);
|
||||||
|
|
||||||
if (!port) {
|
// if (!port) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (data[4] === 0x0a) {
|
// if (data[4] === 0x0a) {
|
||||||
port.busy = false;
|
// port.busy = false;
|
||||||
if (port.finished) {
|
// if (port.finished) {
|
||||||
port.finished();
|
// port.finished();
|
||||||
port.finished = null;
|
// port.finished = null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private _parseSensorMessage (data: Buffer) {
|
private _parseSensorMessage (data: Buffer) {
|
||||||
|
|
||||||
if (data[3] === this._voltagePort) {
|
// if (data[3] === this._voltagePort) {
|
||||||
const voltageRaw = data.readUInt16LE(4);
|
// const voltageRaw = data.readUInt16LE(4);
|
||||||
this._voltage = voltageRaw * this._voltageMaxV / this._voltageMaxRaw;
|
// this._voltage = voltageRaw * this._voltageMaxV / this._voltageMaxRaw;
|
||||||
return;
|
// return;
|
||||||
} else if (data[3] === this._currentPort) {
|
// } else if (data[3] === this._currentPort) {
|
||||||
const currentRaw = data.readUInt16LE(4);
|
// const currentRaw = data.readUInt16LE(4);
|
||||||
this._current = this._currentMaxMA * currentRaw / this._currentMaxRaw;
|
// this._current = this._currentMaxMA * currentRaw / this._currentMaxRaw;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if ((data[3] === 0x3d && this.type === Consts.HubType.CONTROL_PLUS_HUB)) { // Control+ CPU Temperature
|
// if ((data[3] === 0x3d && this.type === Consts.HubType.CONTROL_PLUS_HUB)) { // Control+ CPU Temperature
|
||||||
/**
|
// /**
|
||||||
* Emits when a change is detected on a temperature sensor. Measured in degrees centigrade.
|
// * Emits when a change is detected on a temperature sensor. Measured in degrees centigrade.
|
||||||
* @event LPF2Hub#temp
|
// * @event LPF2Hub#temp
|
||||||
* @param {string} port For Control+ Hubs, port will be "CPU" as the sensor reports CPU temperature.
|
// * @param {string} port For Control+ Hubs, port will be "CPU" as the sensor reports CPU temperature.
|
||||||
* @param {number} temp
|
// * @param {number} temp
|
||||||
*/
|
// */
|
||||||
this.emit("temp", "CPU", ((data.readInt16LE(4) / 900) * 90).toFixed(2));
|
// this.emit("temp", "CPU", ((data.readInt16LE(4) / 900) * 90).toFixed(2));
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const port = this._getPortForPortNumber(data[3]);
|
// const port = this._getPortForPortNumber(data[3]);
|
||||||
|
|
||||||
if (!port) {
|
// if (!port) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (port && port.connected) {
|
// if (port && port.connected) {
|
||||||
switch (port.type) {
|
// switch (port.type) {
|
||||||
case Consts.DeviceType.WEDO2_DISTANCE: {
|
// case Consts.DeviceType.WEDO2_DISTANCE: {
|
||||||
let distance = data[4];
|
// let distance = data[4];
|
||||||
if (data[5] === 1) {
|
// if (data[5] === 1) {
|
||||||
distance = data[4] + 255;
|
// distance = data[4] + 255;
|
||||||
}
|
// }
|
||||||
/**
|
// /**
|
||||||
* Emits when a distance sensor is activated.
|
// * Emits when a distance sensor is activated.
|
||||||
* @event LPF2Hub#distance
|
// * @event LPF2Hub#distance
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} distance Distance, in millimeters.
|
// * @param {number} distance Distance, in millimeters.
|
||||||
*/
|
// */
|
||||||
this.emit("distance", port.id, distance * 10);
|
// this.emit("distance", port.id, distance * 10);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.COLOR_DISTANCE_SENSOR: {
|
// case Consts.DeviceType.COLOR_DISTANCE_SENSOR: {
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Emits when a color sensor is activated.
|
// * Emits when a color sensor is activated.
|
||||||
* @event LPF2Hub#color
|
// * @event LPF2Hub#color
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {Color} color
|
// * @param {Color} color
|
||||||
*/
|
// */
|
||||||
if (data[4] <= 10) {
|
// if (data[4] <= 10) {
|
||||||
this.emit("color", port.id, data[4]);
|
// this.emit("color", port.id, data[4]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
let distance = data[5];
|
// let distance = data[5];
|
||||||
const partial = data[7];
|
// const partial = data[7];
|
||||||
|
|
||||||
if (partial > 0) {
|
// if (partial > 0) {
|
||||||
distance += 1.0 / partial;
|
// distance += 1.0 / partial;
|
||||||
}
|
// }
|
||||||
|
|
||||||
distance = Math.floor(distance * 25.4) - 20;
|
// distance = Math.floor(distance * 25.4) - 20;
|
||||||
|
|
||||||
this.emit("distance", port.id, distance);
|
// this.emit("distance", port.id, distance);
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* A combined color and distance event, emits when the sensor is activated.
|
// * A combined color and distance event, emits when the sensor is activated.
|
||||||
* @event LPF2Hub#colorAndDistance
|
// * @event LPF2Hub#colorAndDistance
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {Color} color
|
// * @param {Color} color
|
||||||
* @param {number} distance Distance, in millimeters.
|
// * @param {number} distance Distance, in millimeters.
|
||||||
*/
|
// */
|
||||||
if (data[4] <= 10) {
|
// if (data[4] <= 10) {
|
||||||
this.emit("colorAndDistance", port.id, data[4], distance);
|
// this.emit("colorAndDistance", port.id, data[4], distance);
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.WEDO2_TILT: {
|
// case Consts.DeviceType.WEDO2_TILT: {
|
||||||
const tiltX = data.readInt8(4);
|
// const tiltX = data.readInt8(4);
|
||||||
const tiltY = data.readInt8(5);
|
// const tiltY = data.readInt8(5);
|
||||||
this._lastTiltX = tiltX;
|
// this._lastTiltX = tiltX;
|
||||||
this._lastTiltY = tiltY;
|
// this._lastTiltY = tiltY;
|
||||||
/**
|
// /**
|
||||||
* Emits when a tilt sensor is activated.
|
// * Emits when a tilt sensor is activated.
|
||||||
* @event LPF2Hub#tilt
|
// * @event LPF2Hub#tilt
|
||||||
* @param {string} port If the event is fired from the Move Hub or Control+ Hub's in-built tilt sensor, the special port "TILT" is used.
|
// * @param {string} port If the event is fired from the Move Hub or Control+ Hub's in-built tilt sensor, the special port "TILT" is used.
|
||||||
* @param {number} x
|
// * @param {number} x
|
||||||
* @param {number} y
|
// * @param {number} y
|
||||||
* @param {number} z (Only available when using a Control+ Hub)
|
// * @param {number} z (Only available when using a Control+ Hub)
|
||||||
*/
|
// */
|
||||||
this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY, this._lastTiltZ);
|
// this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY, this._lastTiltZ);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.BOOST_TACHO_MOTOR: {
|
// case Consts.DeviceType.BOOST_TACHO_MOTOR: {
|
||||||
const rotation = data.readInt32LE(4);
|
// const rotation = data.readInt32LE(4);
|
||||||
/**
|
// /**
|
||||||
* Emits when a rotation sensor is activated.
|
// * Emits when a rotation sensor is activated.
|
||||||
* @event LPF2Hub#rotate
|
// * @event LPF2Hub#rotate
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} rotation
|
// * @param {number} rotation
|
||||||
*/
|
// */
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.BOOST_MOVE_HUB_MOTOR: {
|
// case Consts.DeviceType.BOOST_MOVE_HUB_MOTOR: {
|
||||||
const rotation = data.readInt32LE(4);
|
// const rotation = data.readInt32LE(4);
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: {
|
// case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: {
|
||||||
const rotation = data.readInt32LE(4);
|
// const rotation = data.readInt32LE(4);
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR: {
|
// case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR: {
|
||||||
const rotation = data.readInt32LE(4);
|
// const rotation = data.readInt32LE(4);
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_TILT: {
|
// case Consts.DeviceType.CONTROL_PLUS_TILT: {
|
||||||
const tiltZ = data.readInt16LE(4);
|
// const tiltZ = data.readInt16LE(4);
|
||||||
const tiltY = data.readInt16LE(6);
|
// const tiltY = data.readInt16LE(6);
|
||||||
const tiltX = data.readInt16LE(8);
|
// const tiltX = data.readInt16LE(8);
|
||||||
this._lastTiltX = tiltX;
|
// this._lastTiltX = tiltX;
|
||||||
this._lastTiltY = tiltY;
|
// this._lastTiltY = tiltY;
|
||||||
this._lastTiltZ = tiltZ;
|
// this._lastTiltZ = tiltZ;
|
||||||
this.emit("tilt", "TILT", this._lastTiltX, this._lastTiltY, this._lastTiltZ);
|
// this.emit("tilt", "TILT", this._lastTiltX, this._lastTiltY, this._lastTiltZ);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_GYRO: {
|
// case Consts.DeviceType.CONTROL_PLUS_GYRO: {
|
||||||
const gyroX = Math.round(data.readInt16LE(4) * 7 / 400);
|
// const gyroX = Math.round(data.readInt16LE(4) * 7 / 400);
|
||||||
const gyroY = Math.round(data.readInt16LE(6) * 7 / 400);
|
// const gyroY = Math.round(data.readInt16LE(6) * 7 / 400);
|
||||||
const gyroZ = Math.round(data.readInt16LE(8) * 7 / 400);
|
// const gyroZ = Math.round(data.readInt16LE(8) * 7 / 400);
|
||||||
/**
|
// /**
|
||||||
* Emits when gyroscope detects movement. Measured in DPS - degrees per second.
|
// * Emits when gyroscope detects movement. Measured in DPS - degrees per second.
|
||||||
* @event LPF2Hub#gyro
|
// * @event LPF2Hub#gyro
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} x
|
// * @param {number} x
|
||||||
* @param {number} y
|
// * @param {number} y
|
||||||
* @param {number} z
|
// * @param {number} z
|
||||||
*/
|
// */
|
||||||
this.emit("gyro", "GYRO", gyroX, gyroY, gyroZ);
|
// this.emit("gyro", "GYRO", gyroX, gyroY, gyroZ);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_ACCELEROMETER: {
|
// case Consts.DeviceType.CONTROL_PLUS_ACCELEROMETER: {
|
||||||
const accelX = Math.round(data.readInt16LE(4) / 4.096);
|
// const accelX = Math.round(data.readInt16LE(4) / 4.096);
|
||||||
const accelY = Math.round(data.readInt16LE(6) / 4.096);
|
// const accelY = Math.round(data.readInt16LE(6) / 4.096);
|
||||||
const accelZ = Math.round(data.readInt16LE(8) / 4.096);
|
// const accelZ = Math.round(data.readInt16LE(8) / 4.096);
|
||||||
/**
|
// /**
|
||||||
* Emits when accelerometer detects movement. Measured in mG.
|
// * Emits when accelerometer detects movement. Measured in mG.
|
||||||
* @event LPF2Hub#accel
|
// * @event LPF2Hub#accel
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} x
|
// * @param {number} x
|
||||||
* @param {number} y
|
// * @param {number} y
|
||||||
* @param {number} z
|
// * @param {number} z
|
||||||
*/
|
// */
|
||||||
this.emit("accel", "ACCEL", accelX, accelY, accelZ);
|
// this.emit("accel", "ACCEL", accelX, accelY, accelZ);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.BOOST_TILT: {
|
// case Consts.DeviceType.BOOST_TILT: {
|
||||||
const tiltX = data.readInt8(4);
|
// const tiltX = data.readInt8(4);
|
||||||
const tiltY = data.readInt8(5);
|
// const tiltY = data.readInt8(5);
|
||||||
this._lastTiltX = tiltX;
|
// this._lastTiltX = tiltX;
|
||||||
this._lastTiltY = tiltY;
|
// this._lastTiltY = tiltY;
|
||||||
this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY, this._lastTiltZ);
|
// this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY, this._lastTiltZ);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.POWERED_UP_REMOTE_BUTTON: {
|
// case Consts.DeviceType.POWERED_UP_REMOTE_BUTTON: {
|
||||||
switch (data[4]) {
|
// switch (data[4]) {
|
||||||
case 0x01: {
|
// case 0x01: {
|
||||||
this.emit("button", port.id, Consts.ButtonState.UP);
|
// this.emit("button", port.id, Consts.ButtonState.UP);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case 0xff: {
|
// case 0xff: {
|
||||||
this.emit("button", port.id, Consts.ButtonState.DOWN);
|
// this.emit("button", port.id, Consts.ButtonState.DOWN);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case 0x7f: {
|
// case 0x7f: {
|
||||||
this.emit("button", port.id, Consts.ButtonState.STOP);
|
// this.emit("button", port.id, Consts.ButtonState.STOP);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case 0x00: {
|
// case 0x00: {
|
||||||
this.emit("button", port.id, Consts.ButtonState.RELEASED);
|
// this.emit("button", port.id, Consts.ButtonState.RELEASED);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.DUPLO_TRAIN_BASE_COLOR: {
|
// case Consts.DeviceType.DUPLO_TRAIN_BASE_COLOR: {
|
||||||
if (data[4] <= 10) {
|
// if (data[4] <= 10) {
|
||||||
this.emit("color", port.id, data[4]);
|
// this.emit("color", port.id, data[4]);
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER: {
|
// case Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER: {
|
||||||
/**
|
// /**
|
||||||
* Emits on a speed change.
|
// * Emits on a speed change.
|
||||||
* @event LPF2Hub#speed
|
// * @event LPF2Hub#speed
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} speed
|
// * @param {number} speed
|
||||||
*/
|
// */
|
||||||
const speed = data.readInt16LE(4);
|
// const speed = data.readInt16LE(4);
|
||||||
this.emit("speed", port.id, speed);
|
// this.emit("speed", port.id, speed);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
244
src/puphub.ts
244
src/puphub.ts
@ -36,14 +36,11 @@ export class PUPHub extends LPF2Hub {
|
|||||||
|
|
||||||
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
||||||
super(device, autoSubscribe);
|
super(device, autoSubscribe);
|
||||||
this.type = Consts.HubType.POWERED_UP_HUB;
|
this._type = Consts.HubType.POWERED_UP_HUB;
|
||||||
this._ports = {
|
this._portNames = {
|
||||||
"A": new Port("A", 0),
|
"A": 0,
|
||||||
"B": new Port("B", 1)
|
"B": 1
|
||||||
};
|
};
|
||||||
this.on("attach", (port, type) => {
|
|
||||||
this._combinePorts(port, type);
|
|
||||||
});
|
|
||||||
debug("Discovered Powered UP Hub");
|
debug("Discovered Powered UP Hub");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,239 +55,6 @@ export class PUPHub extends LPF2Hub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the motor speed on a given port.
|
|
||||||
* @method PUPHub#setMotorSpeed
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number | Array.<number>} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
|
||||||
* @param {number} [time] How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely.
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
|
||||||
*/
|
|
||||||
public setMotorSpeed (port: string, speed: number | [number, number], time?: number | boolean) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
|
||||||
throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
|
||||||
}
|
|
||||||
let cancelEventTimer = true;
|
|
||||||
if (typeof time === "boolean") {
|
|
||||||
if (time === true) {
|
|
||||||
cancelEventTimer = false;
|
|
||||||
}
|
|
||||||
time = undefined;
|
|
||||||
}
|
|
||||||
if (cancelEventTimer) {
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (time && typeof time === "number") {
|
|
||||||
|
|
||||||
if (
|
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
|
||||||
) {
|
|
||||||
portObj.busy = true;
|
|
||||||
let data = null;
|
|
||||||
if (this._virtualPorts[portObj.id]) {
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0a, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
|
||||||
} else {
|
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x09, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
|
||||||
}
|
|
||||||
data.writeUInt16LE(time > 65535 ? 65535 : time, 4);
|
|
||||||
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.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
const timeout = global.setTimeout(() => {
|
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, 0x00]);
|
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
return resolve();
|
|
||||||
// @ts-ignore: The type of time is properly checked at the start
|
|
||||||
}, time);
|
|
||||||
portObj.setEventTimer(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR || portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR) {
|
|
||||||
portObj.busy = true;
|
|
||||||
let data = null;
|
|
||||||
if (this._virtualPorts[portObj.id]) {
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x02, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
|
||||||
} else {
|
|
||||||
// @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.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.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ramp the motor speed on a given port.
|
|
||||||
* @method PUPHub#rampMotorSpeed
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
|
||||||
* @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
|
||||||
* @param {number} time How long the ramp should last (in milliseconds).
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
|
||||||
*/
|
|
||||||
public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
|
||||||
.on("changeSpeed", (speed) => {
|
|
||||||
this.setMotorSpeed(port, speed, true);
|
|
||||||
})
|
|
||||||
.on("finished", resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotate a motor by a given angle.
|
|
||||||
* @method PUPHub#setMotorAngle
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number} angle How much the motor should be rotated (in degrees).
|
|
||||||
* @param {number | Array.<number>} [speed=100] For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds.
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command (ie. once the motor is finished).
|
|
||||||
*/
|
|
||||||
public setMotorAngle (port: string, angle: number, speed: number | [number, number] = 100) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
if (!(
|
|
||||||
portObj.type === Consts.DeviceType.BOOST_TACHO_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.BOOST_MOVE_HUB_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
|
||||||
)) {
|
|
||||||
throw new Error("Angle rotation is only available when using a Boost Tacho Motor, Boost Move Hub Motor, Control+ Medium Motor, or Control+ Large Motor");
|
|
||||||
}
|
|
||||||
if (!this._virtualPorts[portObj.id] && speed instanceof Array) {
|
|
||||||
throw new Error(`Port ${portObj.id} can only accept a single speed`);
|
|
||||||
}
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
portObj.busy = true;
|
|
||||||
let data = null;
|
|
||||||
if (this._virtualPorts[portObj.id]) {
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0c, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed instanceof Array ? speed[0] : speed), this._mapSpeed(speed instanceof Array ? speed[1] : speed), 0x64, 0x7f, 0x03]);
|
|
||||||
} else {
|
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
|
||||||
}
|
|
||||||
data.writeUInt32LE(angle, 4);
|
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
portObj.finished = () => {
|
|
||||||
return resolve();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell motor to goto an absolute position
|
|
||||||
* @method PUPHub#setAbsolutePosition
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number} pos The position of the motor to go to
|
|
||||||
* @param {number | Array.<number>} [speed=100] A value between 1 - 100 should be set (Direction does not apply when going to absolute position)
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command (ie. once the motor is finished).
|
|
||||||
*/
|
|
||||||
public setAbsolutePosition (port: string, pos: number, speed: number = 100) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
if (!(
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
|
||||||
)) {
|
|
||||||
throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
|
||||||
}
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
portObj.busy = true;
|
|
||||||
let data = null;
|
|
||||||
if (this._virtualPorts[portObj.id]) {
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
|
||||||
data.writeInt32LE(pos, 4);
|
|
||||||
data.writeInt32LE(pos, 8);
|
|
||||||
} else {
|
|
||||||
// @ts-ignore: The type of speed is properly checked at the start
|
|
||||||
data = Buffer.from([0x81, portObj.value, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, this._mapSpeed(speed), 0x64, 0x7f, 0x03]);
|
|
||||||
data.writeInt32LE(pos, 4);
|
|
||||||
}
|
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
portObj.finished = () => {
|
|
||||||
return resolve();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the current motor position as absolute position zero
|
|
||||||
* @method PUPHub#resetAbsolutePosition
|
|
||||||
* @param {string} port
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command (ie. once the motor is finished).
|
|
||||||
*/
|
|
||||||
public resetAbsolutePosition (port: string) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
if (!(
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR ||
|
|
||||||
portObj.type === Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR
|
|
||||||
)) {
|
|
||||||
throw new Error("Absolute positioning is only available when using a Control+ Medium Motor, or Control+ Large Motor");
|
|
||||||
}
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00]);
|
|
||||||
this.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
return resolve();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the light brightness on a given port.
|
|
||||||
* @method PUPHub#setLightBrightness
|
|
||||||
* @param {string} port
|
|
||||||
* @param {number} brightness Brightness value between 0-100 (0 is off)
|
|
||||||
* @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
|
||||||
*/
|
|
||||||
public setLightBrightness (port: string, brightness: number, time?: number) {
|
|
||||||
const portObj = this._portLookup(port);
|
|
||||||
portObj.cancelEventTimer();
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const data = Buffer.from([0x81, portObj.value, 0x11, 0x51, 0x00, brightness]);
|
|
||||||
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.send(Consts.BLECharacteristic.LPF2_ALL, data);
|
|
||||||
return resolve();
|
|
||||||
}, time);
|
|
||||||
portObj.setEventTimer(timeout);
|
|
||||||
} else {
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected _checkFirmware (version: string) {
|
protected _checkFirmware (version: string) {
|
||||||
if (compareVersion("1.1.00.0004", version) === 1) {
|
if (compareVersion("1.1.00.0004", version) === 1) {
|
||||||
throw new Error(`Your Powered Up Hub's (${this.name}) firmware is out of date and unsupported by this library. Please update it via the official Powered Up app.`);
|
throw new Error(`Your Powered Up Hub's (${this.name}) firmware is out of date and unsupported by this library. Please update it via the official Powered Up app.`);
|
||||||
|
@ -39,10 +39,10 @@ export class PUPRemote extends LPF2Hub {
|
|||||||
|
|
||||||
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
||||||
super(device, autoSubscribe);
|
super(device, autoSubscribe);
|
||||||
this.type = Consts.HubType.POWERED_UP_REMOTE;
|
this._type = Consts.HubType.POWERED_UP_REMOTE;
|
||||||
this._ports = {
|
this._portNames = {
|
||||||
"LEFT": new Port("LEFT", 0),
|
"LEFT": 0,
|
||||||
"RIGHT": new Port("RIGHT", 1)
|
"RIGHT": 1
|
||||||
};
|
};
|
||||||
debug("Discovered Powered UP Remote");
|
debug("Discovered Powered UP Remote");
|
||||||
}
|
}
|
||||||
|
21
src/utils.ts
21
src/utils.ts
@ -1,9 +1,22 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const isWebBluetooth = (typeof navigator !== "undefined" && navigator && navigator.bluetooth);
|
export const isWebBluetooth = (typeof navigator !== "undefined" && navigator && navigator.bluetooth);
|
||||||
|
|
||||||
export function toHex (value: number, length: number = 2) {
|
export const toHex = (value: number, length: number = 2) => {
|
||||||
return value.toString(16).padStart(length, "0");
|
return value.toString(16).padStart(length, "0");
|
||||||
}
|
};
|
||||||
export function toBin (value: number, length: number = 8) {
|
|
||||||
|
export const toBin = (value: number, length: number = 8) => {
|
||||||
return value.toString(2).padStart(length, "0");
|
return value.toString(2).padStart(length, "0");
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const mapSpeed = (speed: number) => {
|
||||||
|
if (speed === 127) {
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
|
if (speed > 100) {
|
||||||
|
speed = 100;
|
||||||
|
} else if (speed < -100) {
|
||||||
|
speed = -100;
|
||||||
|
}
|
||||||
|
return speed;
|
||||||
|
};
|
||||||
|
@ -38,10 +38,10 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
|
|
||||||
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
constructor (device: IBLEAbstraction, autoSubscribe: boolean = true) {
|
||||||
super(device, autoSubscribe);
|
super(device, autoSubscribe);
|
||||||
this.type = Consts.HubType.WEDO2_SMART_HUB;
|
this._type = Consts.HubType.WEDO2_SMART_HUB;
|
||||||
this._ports = {
|
this._portNames = {
|
||||||
"A": new Port("A", 1),
|
"A": 1,
|
||||||
"B": new Port("B", 2)
|
"B": 2
|
||||||
};
|
};
|
||||||
debug("Discovered WeDo 2.0 Smart Hub");
|
debug("Discovered WeDo 2.0 Smart Hub");
|
||||||
}
|
}
|
||||||
@ -115,8 +115,8 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const data = Buffer.from(name, "ascii");
|
const data = Buffer.from(name, "ascii");
|
||||||
// Send this twice, as sometimes the first time doesn't take
|
// Send this twice, as sometimes the first time doesn't take
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_NAME_ID, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_NAME_ID);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_NAME_ID, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_NAME_ID);
|
||||||
this._name = name;
|
this._name = name;
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
@ -132,12 +132,12 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
public setLEDColor (color: number | boolean) {
|
public setLEDColor (color: number | boolean) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let data = Buffer.from([0x06, 0x17, 0x01, 0x01]);
|
let data = Buffer.from([0x06, 0x17, 0x01, 0x01]);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE);
|
||||||
if (typeof color === "boolean") {
|
if (typeof color === "boolean") {
|
||||||
color = 0;
|
color = 0;
|
||||||
}
|
}
|
||||||
data = Buffer.from([0x06, 0x04, 0x01, color]);
|
data = Buffer.from([0x06, 0x04, 0x01, color]);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
*/
|
*/
|
||||||
public shutdown () {
|
public shutdown () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_DISCONNECT, Buffer.from([0x00]), () => {
|
this.send(Buffer.from([0x00]), Consts.BLECharacteristic.WEDO2_DISCONNECT, () => {
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -168,80 +168,80 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
public setLEDRGB (red: number, green: number, blue: number) {
|
public setLEDRGB (red: number, green: number, blue: number) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let data = Buffer.from([0x06, 0x17, 0x01, 0x02]);
|
let data = Buffer.from([0x06, 0x17, 0x01, 0x02]);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE);
|
||||||
data = Buffer.from([0x06, 0x04, 0x03, red, green, blue]);
|
data = Buffer.from([0x06, 0x04, 0x03, red, green, blue]);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Set the motor speed on a given port.
|
// * Set the motor speed on a given port.
|
||||||
* @method WeDo2SmartHub#setMotorSpeed
|
// * @method WeDo2SmartHub#setMotorSpeed
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} [time] How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely.
|
// * @param {number} [time] How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely.
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
// * @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the motor is finished.
|
||||||
*/
|
// */
|
||||||
public setMotorSpeed (port: string, speed: number, time?: number | boolean) {
|
// public setMotorSpeed (port: string, speed: number, time?: number | boolean) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
let cancelEventTimer = true;
|
// let cancelEventTimer = true;
|
||||||
if (typeof time === "boolean") {
|
// if (typeof time === "boolean") {
|
||||||
if (time === true) {
|
// if (time === true) {
|
||||||
cancelEventTimer = false;
|
// cancelEventTimer = false;
|
||||||
}
|
// }
|
||||||
time = undefined;
|
// time = undefined;
|
||||||
}
|
// }
|
||||||
if (cancelEventTimer) {
|
// if (cancelEventTimer) {
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
}
|
// }
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([portObj.value, 0x01, 0x02, this._mapSpeed(speed)]));
|
// this.send(Buffer.from([portObj.value, 0x01, 0x02, this._mapSpeed(speed)]), Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
if (time && typeof time === "number") {
|
// if (time && typeof time === "number") {
|
||||||
const timeout = global.setTimeout(() => {
|
// const timeout = global.setTimeout(() => {
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, Buffer.from([portObj.value, 0x01, 0x02, 0x00]));
|
// this.send(Buffer.from([portObj.value, 0x01, 0x02, 0x00]), Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
return resolve();
|
// return resolve();
|
||||||
}, time);
|
// }, time);
|
||||||
portObj.setEventTimer(timeout);
|
// portObj.setEventTimer(timeout);
|
||||||
} else {
|
// } else {
|
||||||
return resolve();
|
// return resolve();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Ramp the motor speed on a given port.
|
// * Ramp the motor speed on a given port.
|
||||||
* @method WeDo2SmartHub#rampMotorSpeed
|
// * @method WeDo2SmartHub#rampMotorSpeed
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
// * @param {number} toSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
|
||||||
* @param {number} time How long the ramp should last (in milliseconds).
|
// * @param {number} time How long the ramp should last (in milliseconds).
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
// * @returns {Promise} Resolved upon successful completion of command.
|
||||||
*/
|
// */
|
||||||
public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
// public rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
// this._calculateRamp(fromSpeed, toSpeed, time, portObj)
|
||||||
.on("changeSpeed", (speed) => {
|
// .on("changeSpeed", (speed) => {
|
||||||
this.setMotorSpeed(port, speed, true);
|
// this.setMotorSpeed(port, speed, true);
|
||||||
})
|
// })
|
||||||
.on("finished", resolve);
|
// .on("finished", resolve);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Fully (hard) stop the motor on a given port.
|
// * Fully (hard) stop the motor on a given port.
|
||||||
* @method WeDo2SmartHub#brakeMotor
|
// * @method WeDo2SmartHub#brakeMotor
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @returns {Promise} Resolved upon successful completion of command.
|
// * @returns {Promise} Resolved upon successful completion of command.
|
||||||
*/
|
// */
|
||||||
public brakeMotor (port: string) {
|
// public brakeMotor (port: string) {
|
||||||
return this.setMotorSpeed(port, 127);
|
// return this.setMotorSpeed(port, 127);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,41 +256,41 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
const data = Buffer.from([0x05, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00]);
|
const data = Buffer.from([0x05, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00]);
|
||||||
data.writeUInt16LE(frequency, 3);
|
data.writeUInt16LE(frequency, 3);
|
||||||
data.writeUInt16LE(time, 5);
|
data.writeUInt16LE(time, 5);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data);
|
this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
global.setTimeout(resolve, time);
|
global.setTimeout(resolve, time);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Set the light brightness on a given port.
|
// * Set the light brightness on a given port.
|
||||||
* @method WeDo2SmartHub#setLightBrightness
|
// * @method WeDo2SmartHub#setLightBrightness
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} brightness Brightness value between 0-100 (0 is off)
|
// * @param {number} brightness Brightness value between 0-100 (0 is off)
|
||||||
* @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
// * @param {number} [time] How long to turn the light on (in milliseconds). Leave empty to turn the light on indefinitely.
|
||||||
* @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
// * @returns {Promise} Resolved upon successful completion of command. If time is specified, this is once the light is turned off.
|
||||||
*/
|
// */
|
||||||
public setLightBrightness (port: string, brightness: number, time?: number) {
|
// public setLightBrightness (port: string, brightness: number, time?: number) {
|
||||||
const portObj = this._portLookup(port);
|
// const portObj = this._portLookup(port);
|
||||||
portObj.cancelEventTimer();
|
// portObj.cancelEventTimer();
|
||||||
return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
const data = Buffer.from([portObj.value, 0x01, 0x02, brightness]);
|
// const data = Buffer.from([portObj.value, 0x01, 0x02, brightness]);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data);
|
// this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
if (time) {
|
// if (time) {
|
||||||
const timeout = global.setTimeout(() => {
|
// const timeout = global.setTimeout(() => {
|
||||||
const data = Buffer.from([portObj.value, 0x01, 0x02, 0x00]);
|
// const data = Buffer.from([portObj.value, 0x01, 0x02, 0x00]);
|
||||||
this.send(Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE, data);
|
// this.send(data, Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE);
|
||||||
return resolve();
|
// return resolve();
|
||||||
}, time);
|
// }, time);
|
||||||
portObj.setEventTimer(timeout);
|
// portObj.setEventTimer(timeout);
|
||||||
} else {
|
// } else {
|
||||||
return resolve();
|
// return resolve();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
public send (uuid: string, message: Buffer, callback?: () => void) {
|
public send (message: Buffer, uuid: string, callback?: () => void) {
|
||||||
if (debug.enabled) {
|
if (debug.enabled) {
|
||||||
debug(`Sent Message (${this._getCharacteristicNameFromUUID(uuid)})`, message);
|
debug(`Sent Message (${this._getCharacteristicNameFromUUID(uuid)})`, message);
|
||||||
}
|
}
|
||||||
@ -299,12 +299,12 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
|
|
||||||
|
|
||||||
protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) {
|
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);
|
this.send(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) {
|
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);
|
this.send(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x00]), Consts.BLECharacteristic.WEDO2_PORT_TYPE_WRITE, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -361,7 +361,7 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._registerDeviceAttachment(device);
|
this._attachDevice(device);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,101 +379,101 @@ export class WeDo2SmartHub extends Hub {
|
|||||||
|
|
||||||
private _parseSensorMessage (data: Buffer) {
|
private _parseSensorMessage (data: Buffer) {
|
||||||
|
|
||||||
debug("Received Message (WEDO2_SENSOR_VALUE)", data);
|
// 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.
|
||||||
* @event WeDo2SmartHub#button
|
// * @event WeDo2SmartHub#button
|
||||||
* @param {string} button
|
// * @param {string} button
|
||||||
* @param {ButtonState} state
|
// * @param {ButtonState} state
|
||||||
*/
|
// */
|
||||||
this.emit("button", "GREEN", Consts.ButtonState.PRESSED);
|
// this.emit("button", "GREEN", Consts.ButtonState.PRESSED);
|
||||||
return;
|
// return;
|
||||||
} else if (data[0] === 0x00) {
|
// } else if (data[0] === 0x00) {
|
||||||
this.emit("button", "GREEN", Consts.ButtonState.RELEASED);
|
// this.emit("button", "GREEN", Consts.ButtonState.RELEASED);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Voltage
|
// // Voltage
|
||||||
if (data[1] === 0x03) {
|
// if (data[1] === 0x03) {
|
||||||
const voltage = data.readInt16LE(2);
|
// const voltage = data.readInt16LE(2);
|
||||||
this._voltage = voltage / 40;
|
// this._voltage = voltage / 40;
|
||||||
// Current
|
// // Current
|
||||||
} else if (data[1] === 0x04) {
|
// } else if (data[1] === 0x04) {
|
||||||
const current = data.readInt16LE(2);
|
// const current = data.readInt16LE(2);
|
||||||
this._current = current / 1000;
|
// this._current = current / 1000;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const port = this._getPortForPortNumber(data[1]);
|
// const port = this._getPortForPortNumber(data[1]);
|
||||||
|
|
||||||
if (!port) {
|
// if (!port) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (port && port.connected) {
|
// if (port && port.connected) {
|
||||||
switch (port.type) {
|
// switch (port.type) {
|
||||||
case Consts.DeviceType.WEDO2_DISTANCE: {
|
// case Consts.DeviceType.WEDO2_DISTANCE: {
|
||||||
let distance = data[2];
|
// let distance = data[2];
|
||||||
if (data[3] === 1) {
|
// if (data[3] === 1) {
|
||||||
distance = data[2] + 255;
|
// distance = data[2] + 255;
|
||||||
}
|
// }
|
||||||
/**
|
// /**
|
||||||
* Emits when a distance sensor is activated.
|
// * Emits when a distance sensor is activated.
|
||||||
* @event WeDo2SmartHub#distance
|
// * @event WeDo2SmartHub#distance
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} distance Distance, in millimeters.
|
// * @param {number} distance Distance, in millimeters.
|
||||||
*/
|
// */
|
||||||
this.emit("distance", port.id, distance * 10);
|
// this.emit("distance", port.id, distance * 10);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.COLOR_DISTANCE_SENSOR: {
|
// case Consts.DeviceType.COLOR_DISTANCE_SENSOR: {
|
||||||
const distance = data[2];
|
// const distance = data[2];
|
||||||
/**
|
// /**
|
||||||
* Emits when a color sensor is activated.
|
// * Emits when a color sensor is activated.
|
||||||
* @event WeDo2SmartHub#color
|
// * @event WeDo2SmartHub#color
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {Color} color
|
// * @param {Color} color
|
||||||
*/
|
// */
|
||||||
this.emit("color", port.id, distance);
|
// this.emit("color", port.id, distance);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.WEDO2_TILT: {
|
// case Consts.DeviceType.WEDO2_TILT: {
|
||||||
this._lastTiltX = data.readInt8(2);
|
// this._lastTiltX = data.readInt8(2);
|
||||||
this._lastTiltY = data.readInt8(3);
|
// this._lastTiltY = data.readInt8(3);
|
||||||
/**
|
// /**
|
||||||
* Emits when a tilt sensor is activated.
|
// * Emits when a tilt sensor is activated.
|
||||||
* @event WeDo2SmartHub#tilt
|
// * @event WeDo2SmartHub#tilt
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} x
|
// * @param {number} x
|
||||||
* @param {number} y
|
// * @param {number} y
|
||||||
*/
|
// */
|
||||||
this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY);
|
// this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.BOOST_TACHO_MOTOR: {
|
// case Consts.DeviceType.BOOST_TACHO_MOTOR: {
|
||||||
const rotation = data.readInt32LE(2);
|
// const rotation = data.readInt32LE(2);
|
||||||
/**
|
// /**
|
||||||
* Emits when a rotation sensor is activated.
|
// * Emits when a rotation sensor is activated.
|
||||||
* @event WeDo2SmartHub#rotate
|
// * @event WeDo2SmartHub#rotate
|
||||||
* @param {string} port
|
// * @param {string} port
|
||||||
* @param {number} rotation
|
// * @param {number} rotation
|
||||||
*/
|
// */
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: {
|
// case Consts.DeviceType.CONTROL_PLUS_LARGE_MOTOR: {
|
||||||
const rotation = data.readInt32LE(2);
|
// const rotation = data.readInt32LE(2);
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR: {
|
// case Consts.DeviceType.CONTROL_PLUS_XLARGE_MOTOR: {
|
||||||
const rotation = data.readInt32LE(2);
|
// const rotation = data.readInt32LE(2);
|
||||||
this.emit("rotate", port.id, rotation);
|
// this.emit("rotate", port.id, rotation);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user