Bug fixes, hubs now wait for hub properties before being connected
This commit is contained in:
parent
bc644c85b2
commit
035017617e
37
examples/multiple_motors.js
Normal file
37
examples/multiple_motors.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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}!`);
|
||||||
|
|
||||||
|
const motorA = await hub.waitForDeviceAtPort("A");
|
||||||
|
console.log("Got motor A");
|
||||||
|
const motorB = await hub.waitForDeviceAtPort("B");
|
||||||
|
console.log("Got motor B");
|
||||||
|
const motorC = await hub.waitForDeviceAtPort("C");
|
||||||
|
console.log("Got motor C");
|
||||||
|
const motorD = await hub.waitForDeviceAtPort("D");
|
||||||
|
console.log("Got motor D");
|
||||||
|
|
||||||
|
motorA.setPower(30);
|
||||||
|
motorB.setPower(30);
|
||||||
|
motorC.setPower(30);
|
||||||
|
motorD.setPower(30);
|
||||||
|
|
||||||
|
hub.on("disconnect", () => {
|
||||||
|
console.log("Hub disconnected");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -41,7 +41,7 @@ export class HubLED extends Device {
|
|||||||
public setRGB (red: number, green: number, blue: number) {
|
public setRGB (red: number, green: number, blue: number) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.subscribe(HubLED.Mode.RGB);
|
this.subscribe(HubLED.Mode.RGB);
|
||||||
this.writeDirect(0x00, Buffer.from([red, green, blue]));
|
this.writeDirect(0x01, Buffer.from([red, green, blue]));
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,11 @@ export class BaseHub extends EventEmitter {
|
|||||||
|
|
||||||
private _type: Consts.HubType;
|
private _type: Consts.HubType;
|
||||||
private _portMap: {[portName: string]: number} = {};
|
private _portMap: {[portName: string]: number} = {};
|
||||||
private _attachCallbacks: ((device: Device) => void)[] = [];
|
private _attachCallbacks: ((device: Device) => boolean)[] = [];
|
||||||
|
|
||||||
constructor (device: IBLEAbstraction, portMap: {[portName: string]: number} = {}, type: Consts.HubType = Consts.HubType.UNKNOWN) {
|
constructor (device: IBLEAbstraction, portMap: {[portName: string]: number} = {}, type: Consts.HubType = Consts.HubType.UNKNOWN) {
|
||||||
super();
|
super();
|
||||||
|
this.setMaxListeners(20); // Technic Medium Hub has 9 built in devices + 4 external ports. Node.js throws a warning after 11 attached event listeners.
|
||||||
this._type = type;
|
this._type = type;
|
||||||
this._bleDevice = device;
|
this._bleDevice = device;
|
||||||
this._portMap = portMap;
|
this._portMap = portMap;
|
||||||
@ -183,7 +184,7 @@ export class BaseHub extends EventEmitter {
|
|||||||
|
|
||||||
public getDeviceAtPort (portName: string) {
|
public getDeviceAtPort (portName: string) {
|
||||||
const portId = this._portMap[portName];
|
const portId = this._portMap[portName];
|
||||||
if (portId) {
|
if (portId !== undefined) {
|
||||||
return this._attachedDevices[portId];
|
return this._attachedDevices[portId];
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Port ${portName} does not exist on this hub type`);
|
throw new Error(`Port ${portName} does not exist on this hub type`);
|
||||||
@ -199,7 +200,10 @@ export class BaseHub extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this._attachCallbacks.push((device) => {
|
this._attachCallbacks.push((device) => {
|
||||||
if (device.portName === portName) {
|
if (device.portName === portName) {
|
||||||
return resolve(device);
|
resolve(device);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -224,7 +228,10 @@ export class BaseHub extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this._attachCallbacks.push((device) => {
|
this._attachCallbacks.push((device) => {
|
||||||
if (device.type === deviceType) {
|
if (device.type === deviceType) {
|
||||||
return resolve(device);
|
resolve(device);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -289,9 +296,15 @@ export class BaseHub extends EventEmitter {
|
|||||||
* @param {Device} device
|
* @param {Device} device
|
||||||
*/
|
*/
|
||||||
this.emit("attach", device);
|
this.emit("attach", device);
|
||||||
this._attachCallbacks.forEach((callback) => {
|
debug(`Attached device type ${device.type} (${Consts.DeviceTypeNames[device.type]}) on port ${device.portName} (${device.portId})`);
|
||||||
callback(device);
|
|
||||||
});
|
let i = this._attachCallbacks.length;
|
||||||
|
while (i--) {
|
||||||
|
const callback = this._attachCallbacks[i];
|
||||||
|
if (callback(device)) {
|
||||||
|
this._attachCallbacks.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -303,6 +316,7 @@ export class BaseHub extends EventEmitter {
|
|||||||
* @param {Device} device
|
* @param {Device} device
|
||||||
*/
|
*/
|
||||||
this.emit("detach", device);
|
this.emit("detach", device);
|
||||||
|
debug(`Detached device type ${device.type} (${Consts.DeviceTypeNames[device.type]}) on port ${device.portName} (${device.portId})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,20 +17,24 @@ export class LPF2Hub extends BaseHub {
|
|||||||
|
|
||||||
private _messageBuffer: Buffer = Buffer.alloc(0);
|
private _messageBuffer: Buffer = Buffer.alloc(0);
|
||||||
|
|
||||||
|
private _propertyRequestCallbacks: {[property: number]: ((data: Buffer) => void)} = {};
|
||||||
|
|
||||||
|
|
||||||
public connect () {
|
public connect () {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
|
debug("LPF2Hub connecting");
|
||||||
await super.connect();
|
await super.connect();
|
||||||
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));
|
||||||
await this.sleep(100);
|
await this.sleep(500);
|
||||||
this.send(Buffer.from([0x01, 0x02, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate button reports
|
this._requestHubPropertyReports(0x02); // Activate button reports
|
||||||
this.send(Buffer.from([0x01, 0x03, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request firmware version
|
await this._requestHubPropertyValue(0x03); // Request firmware version
|
||||||
this.send(Buffer.from([0x01, 0x04, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request hardware version
|
await this._requestHubPropertyValue(0x04); // Request hardware version
|
||||||
this.send(Buffer.from([0x01, 0x05, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate RSSI updates
|
this._requestHubPropertyReports(0x05); // Activate RSSI updates
|
||||||
this.send(Buffer.from([0x01, 0x06, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate battery level reports
|
this._requestHubPropertyReports(0x06); // Activate battery level reports
|
||||||
this.send(Buffer.from([0x01, 0x0d, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request primary MAC address
|
await this._requestHubPropertyValue(0x0d); // Request primary MAC address
|
||||||
this.emit("connect");
|
this.emit("connect");
|
||||||
|
debug("LPF2Hub connected");
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -131,7 +135,12 @@ export class LPF2Hub extends BaseHub {
|
|||||||
|
|
||||||
switch (message[2]) {
|
switch (message[2]) {
|
||||||
case 0x01: {
|
case 0x01: {
|
||||||
this._parseDeviceInfo(message);
|
const property = message[3];
|
||||||
|
const callback = this._propertyRequestCallbacks[property];
|
||||||
|
if (callback) {
|
||||||
|
callback(message);
|
||||||
|
}
|
||||||
|
delete this._propertyRequestCallbacks[property];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x04: {
|
case 0x04: {
|
||||||
@ -164,7 +173,23 @@ export class LPF2Hub extends BaseHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private _parseDeviceInfo (message: Buffer) {
|
private _requestHubPropertyValue (property: number) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this._propertyRequestCallbacks[property] = (message) => {
|
||||||
|
this._parseHubPropertyResponse(message);
|
||||||
|
return resolve();
|
||||||
|
};
|
||||||
|
this.send(Buffer.from([0x01, property, 0x05]), Consts.BLECharacteristic.LPF2_ALL);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _requestHubPropertyReports (property: number) {
|
||||||
|
this.send(Buffer.from([0x01, property, 0x02]), Consts.BLECharacteristic.LPF2_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _parseHubPropertyResponse (message: Buffer) {
|
||||||
|
|
||||||
// Button press reports
|
// Button press reports
|
||||||
if (message[3] === 0x02) {
|
if (message[3] === 0x02) {
|
||||||
@ -356,45 +381,6 @@ export class LPF2Hub extends BaseHub {
|
|||||||
device.receive(message);
|
device.receive(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
|
||||||
// * @event LPF2Hub#temp
|
|
||||||
// * @param {string} port For Control+ Hubs, port will be "CPU" as the sensor reports CPU temperature.
|
|
||||||
// * @param {number} temp
|
|
||||||
// */
|
|
||||||
// this.emit("temp", "CPU", ((data.readInt16LE(4) / 900) * 90).toFixed(2));
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const port = this._getPortForPortNumber(data[3]);
|
|
||||||
|
|
||||||
// if (!port) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (port && port.connected) {
|
|
||||||
// switch (port.type) {
|
|
||||||
// case Consts.DeviceType.DUPLO_TRAIN_BASE_COLOR: {
|
|
||||||
// if (data[4] <= 10) {
|
|
||||||
// this.emit("color", port.id, data[4]);
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER: {
|
|
||||||
// /**
|
|
||||||
// * Emits on a speed change.
|
|
||||||
// * @event LPF2Hub#speed
|
|
||||||
// * @param {string} port
|
|
||||||
// * @param {number} speed
|
|
||||||
// */
|
|
||||||
// const speed = data.readInt16LE(4);
|
|
||||||
// this.emit("speed", port.id, speed);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user