node-poweredup/src/poweredup-node.ts
2022-01-18 17:02:35 -08:00

215 lines
5.5 KiB
TypeScript

import { Peripheral } from "@abandonware/noble";
import { NobleDevice } from "./nobleabstraction";
import { BaseHub } from "./hubs/basehub";
import { DuploTrainBase } from "./hubs/duplotrainbase";
import { Hub } from "./hubs/hub";
import { Mario } from "./hubs/mario";
import { MoveHub } from "./hubs/movehub";
import { RemoteControl } from "./hubs/remotecontrol";
import { TechnicMediumHub } from "./hubs/technicmediumhub";
import { WeDo2SmartHub } from "./hubs/wedo2smarthub";
import * as Consts from "./consts";
import { EventEmitter } from "events";
import Debug = require("debug");
const debug = Debug("poweredup");
import noble = require("@abandonware/noble");
import { TechnicSmallHub } from "./hubs/technicsmallhub";
let ready = false;
let wantScan = false;
let discoveryEventAttached = false;
const startScanning = () => {
noble.startScanning([
Consts.BLEService.LPF2_HUB,
Consts.BLEService.WEDO2_SMART_HUB
]);
};
noble.on("stateChange", (state: string) => {
ready = (state === "poweredOn");
if (ready) {
if (wantScan) {
debug("Scanning started");
startScanning();
}
noble.on('scanStop', () => {
setTimeout(() => {
startScanning();
}, 1000);
});
} else {
noble.stopScanning();
}
});
/**
* @class PoweredUP
* @extends EventEmitter
*/
export class PoweredUP extends EventEmitter {
private _connectedHubs: {[uuid: string]: BaseHub} = {};
constructor () {
super();
this._discoveryEventHandler = this._discoveryEventHandler.bind(this);
}
/**
* Begin scanning for Powered UP Hub devices.
* @method PoweredUP#scan
*/
public async scan () {
wantScan = true;
if (!discoveryEventAttached) {
noble.on("discover", this._discoveryEventHandler);
discoveryEventAttached = true;
}
if (ready) {
debug("Scanning started");
startScanning();
}
return true;
}
/**
* Stop scanning for Powered UP Hub devices.
* @method PoweredUP#stop
*/
public stop () {
wantScan = false;
if (discoveryEventAttached) {
noble.removeListener("discover", this._discoveryEventHandler);
discoveryEventAttached = false;
}
noble.stopScanning();
}
/**
* Retrieve a list of Powered UP Hubs.
* @method PoweredUP#getHubs
* @returns {BaseHub[]}
*/
public getHubs () {
return Object.values(this._connectedHubs);
}
/**
* Retrieve a Powered UP Hub by UUID.
* @method PoweredUP#getHubByUUID
* @param {string} uuid
* @returns {BaseHub | null}
*/
public getHubByUUID (uuid: string) {
return this._connectedHubs[uuid];
}
/**
* Retrieve a Powered UP Hub by primary MAC address.
* @method PoweredUP#getHubByPrimaryMACAddress
* @param {string} address
* @returns {BaseHub}
*/
public getHubByPrimaryMACAddress (address: string) {
return Object.values(this._connectedHubs).filter((hub) => hub.primaryMACAddress === address)[0];
}
/**
* Retrieve a list of Powered UP Hub by name.
* @method PoweredUP#getHubsByName
* @param {string} name
* @returns {BaseHub[]}
*/
public getHubsByName (name: string) {
return Object.values(this._connectedHubs).filter((hub) => hub.name === name);
}
/**
* Retrieve a list of Powered UP Hub by type.
* @method PoweredUP#getHubsByType
* @param {string} name
* @returns {BaseHub[]}
*/
public getHubsByType (hubType: number) {
return Object.values(this._connectedHubs).filter((hub) => hub.type === hubType);
}
private async _discoveryEventHandler (peripheral: Peripheral) {
peripheral.removeAllListeners();
const device = new NobleDevice(peripheral);
let hub: BaseHub;
if (WeDo2SmartHub.IsWeDo2SmartHub(peripheral)) {
hub = new WeDo2SmartHub(device);
} else if (MoveHub.IsMoveHub(peripheral)) {
hub = new MoveHub(device);
} else if (Hub.IsHub(peripheral)) {
hub = new Hub(device);
} else if (RemoteControl.IsRemoteControl(peripheral)) {
hub = new RemoteControl(device);
} else if (DuploTrainBase.IsDuploTrainBase(peripheral)) {
hub = new DuploTrainBase(device);
} else if (TechnicSmallHub.IsTechnicSmallHub(peripheral)) {
hub = new TechnicSmallHub(device);
} else if (TechnicMediumHub.IsTechnicMediumHub(peripheral)) {
hub = new TechnicMediumHub(device);
} else if (Mario.IsMario(peripheral)) {
hub = new Mario(device);
} else {
return;
}
device.on("discoverComplete", () => {
hub.on("connect", () => {
debug(`Hub ${hub.uuid} connected`);
this._connectedHubs[hub.uuid] = hub;
});
hub.on("disconnect", () => {
debug(`Hub ${hub.uuid} disconnected`);
delete this._connectedHubs[hub.uuid];
if (wantScan) {
startScanning();
}
});
debug(`Hub ${hub.uuid} discovered`);
/**
* Emits when a Powered UP Hub device is found.
* @event PoweredUP#discover
* @param {WeDo2SmartHub | MoveHub | TechnicMediumHub | RemoteControl | DuploTrainBase} hub
*/
this.emit("discover", hub);
});
}
}