diff --git a/src/devices/device.ts b/src/devices/device.ts index 42ddb1b..fc34d28 100644 --- a/src/devices/device.ts +++ b/src/devices/device.ts @@ -28,6 +28,7 @@ export class Device extends EventEmitter { this._type = type; this._modeMap = modeMap; this._isWeDo2SmartHub = (this.hub.type === Consts.HubType.WEDO2_SMART_HUB); + this._isVirtualPort = this.hub.isPortVirtual(portId); const eventAttachListener = (event: string) => { if (event === "detach") { @@ -87,6 +88,10 @@ export class Device extends EventEmitter { return this._isWeDo2SmartHub; } + protected get isVirtualPort () { + return this._isVirtualPort; + } + public writeDirect (mode: number, data: Buffer, callback?: () => void) { if (this.isWeDo2SmartHub) { this.send(Buffer.concat([Buffer.from([this.portId, 0x01, 0x02]), data]), Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE); diff --git a/src/hubs/basehub.ts b/src/hubs/basehub.ts index 4f43ec3..fb6f0d1 100644 --- a/src/hubs/basehub.ts +++ b/src/hubs/basehub.ts @@ -50,11 +50,11 @@ export class BaseHub extends EventEmitter { protected _batteryLevel: number = 100; protected _rssi: number = -60; protected _portMap: {[portName: string]: number} = {}; + protected _virtualPorts: number[] = []; protected _bleDevice: IBLEAbstraction; private _type: Consts.HubType; - private _virtualPorts: number[] = []; private _attachCallbacks: Array<((device: Device) => boolean)> = []; constructor (bleDevice: IBLEAbstraction, portMap: {[portName: string]: number} = {}, type: Consts.HubType = Consts.HubType.UNKNOWN) { @@ -62,7 +62,7 @@ export class BaseHub extends EventEmitter { this.setMaxListeners(23); // Technic Medium Hub has 9 built in devices + 4 external ports. Node.js throws a warning after 10 attached event listeners. this._type = type; this._bleDevice = bleDevice; - this._portMap = portMap; + this._portMap = Object.assign({}, portMap); bleDevice.on("disconnect", () => { /** * Emits when the hub is disconnected. diff --git a/src/hubs/lpf2hub.ts b/src/hubs/lpf2hub.ts index adeab88..0efdb31 100644 --- a/src/hubs/lpf2hub.ts +++ b/src/hubs/lpf2hub.ts @@ -273,32 +273,28 @@ export class LPF2Hub extends BaseHub { const device = this._getDeviceByPortId(portId); if (device) { this._detachDevice(device); + if (this.isPortVirtual(portId)) { + const portName = this.getPortNameForPortId(portId); + if (portName) { + delete this._portMap[portName]; + } + this._virtualPorts = this._virtualPorts.filter((virtualPortId) => virtualPortId !== portId); + } } + + // Handle virtual port creation + } else if (event === 0x02) { + const firstPortName = this.getPortNameForPortId(message[7]); + const secondPortName = this.getPortNameForPortId(message[8]); + // @ts-ignore NK These should never be undefined + const virtualPortName = firstPortName + secondPortName; + const virtualPortId = message[3]; + this._portMap[virtualPortName] = virtualPortId; + this._virtualPorts.push(virtualPortId); + const device = this._createDevice(deviceType, virtualPortId); + this._attachDevice(device); } - // let port = this._getPortForPortNumber(data[3]); - - // if (!port) { - // if (data[4] === 0x02) { - // const portA = this._getPortForPortNumber(data[7]); - // const portB = this._getPortForPortNumber(data[8]); - // if (portA && portB) { - // this._virtualPorts[`${portA.id}${portB.id}`] = new Port(`${portA.id}${portB.id}`, data[3]); - // port = this._getPortForPortNumber(data[3]); - // if (port) { - // port.connected = true; - // this._registerDeviceAttachment(port, deviceType); - // } else { - // return; - // } - // } else { - // return; - // } - // } else { - // return; - // } - // } - } diff --git a/src/interfaces.ts b/src/interfaces.ts index ea7111c..3b399f1 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -21,4 +21,5 @@ export interface IDeviceInterface extends EventEmitter { getPortNameForPortId: (portId: number) => string | undefined; send: (message: Buffer, uuid: string, callback?: () => void) => void; subscribe: (portId: number, deviceType: number, mode: number) => void; + isPortVirtual: (portId: number) => boolean; }