import { EventEmitter } from "events" ; import { IBLEAbstraction } from "../interfaces" ; import { ColorDistanceSensor } from "../devices/colordistancesensor" ; import { CurrentSensor } from "../devices/currentsensor" ; import { Device } from "../devices/device" ; import { DuploTrainBaseColorSensor } from "../devices/duplotrainbasecolorsensor" ; import { DuploTrainBaseMotor } from "../devices/duplotrainbasemotor" ; import { DuploTrainBaseSpeaker } from "../devices/duplotrainbasespeaker" ; import { DuploTrainBaseSpeedometer } from "../devices/duplotrainbasespeedometer" ; import { HubLED } from "../devices/hubled" ; import { Light } from "../devices/light" ; import { MarioAccelerometer } from "../devices/marioaccelerometer" ; import { MarioBarcodeSensor } from "../devices/mariobarcodesensor" ; import { MarioPantsSensor } from "../devices/mariopantssensor" ; import { MediumLinearMotor } from "../devices/mediumlinearmotor" ; import { MotionSensor } from "../devices/motionsensor" ; import { MoveHubMediumLinearMotor } from "../devices/movehubmediumlinearmotor" ; import { MoveHubTiltSensor } from "../devices/movehubtiltsensor" ; import { PiezoBuzzer } from "../devices/piezobuzzer" ; import { RemoteControlButton } from "../devices/remotecontrolbutton" ; import { SimpleMediumLinearMotor } from "../devices/simplemediumlinearmotor" ; import { TechnicColorSensor } from "../devices/techniccolorsensor" ; import { TechnicDistanceSensor } from "../devices/technicdistancesensor" ; import { TechnicForceSensor } from "../devices/technicforcesensor" ; import { TechnicLargeAngularMotor } from "../devices/techniclargeangularmotor" ; import { TechnicLargeLinearMotor } from "../devices/techniclargelinearmotor" ; import { TechnicSmallAngularMotor } from "../devices/technicsmallangularmotor" ; import { TechnicMediumAngularMotor } from "../devices/technicmediumangularmotor" ; import { TechnicMediumHubAccelerometerSensor } from "../devices/technicmediumhubaccelerometersensor" ; import { TechnicMediumHubGyroSensor } from "../devices/technicmediumhubgyrosensor" ; import { TechnicMediumHubTiltSensor } from "../devices/technicmediumhubtiltsensor" ; import { TechnicXLargeLinearMotor } from "../devices/technicxlargelinearmotor" ; import { TiltSensor } from "../devices/tiltsensor" ; import { TrainMotor } from "../devices/trainmotor" ; import { VoltageSensor } from "../devices/voltagesensor" ; import * as Consts from "../consts" ; import Debug = require ( "debug" ) ; import { Technic3x3ColorLightMatrix } from "../devices/technic3x3colorlightmatrix" ; const debug = Debug ( "basehub" ) ; class extends EventEmitter export class BaseHub extends EventEmitter { protected _attachedDevices : { [ portId ] : Device ; } = { } ; protected _name : string = "" ; protected _firmwareVersion : string = "0.0.00.0000" ; protected _hardwareVersion : string = "0.0.00.0000" ; protected _primaryMACAddress : string = "00:00:00:00:00:00" ; protected _batteryLevel : number = 100 ; protected _rssi : number = - 60 ; protected _portMap : { [ portName ] : number ; } = { } ; protected _virtualPorts : number [ ] = [ ] ; protected _bleDevice : IBLEAbstraction ; private _type : Consts . HubType ; private _attachCallbacks : ( ( device : Device ) => boolean ) [ ] = [ ] ; constructor ( bleDevice , portMap = { } , type = Consts . HubType . UNKNOWN ) { super ( ) ; this . setMaxListeners ( 23 ) ; this . _type = type ; this . _bleDevice = bleDevice ; this . _portMap = Object . assign ( { } , portMap ) ; bleDevice . on ( "disconnect" , ( ) => { event this . emit ( "disconnect" ) ; } ) ; } readonly property public get name ( ) { return this . _bleDevice . name ; } readonly property public get type ( ) { return this . _type ; } readonly property public get ports ( ) { return Object . keys ( this . _portMap ) ; } readonly property public get firmwareVersion ( ) { return this . _firmwareVersion ; } readonly property public get hardwareVersion ( ) { return this . _hardwareVersion ; } readonly property public get primaryMACAddress ( ) { return this . _primaryMACAddress ; } readonly property public get uuid ( ) { return this . _bleDevice . uuid ; } readonly property public get batteryLevel ( ) { return this . _batteryLevel ; } readonly property public get rssi ( ) { return this . _rssi ; } method returns { Promise } public connect ( ) { if ( this . _bleDevice . connecting ) { throw new Error ( "Already connecting" ) ; } else if ( this . _bleDevice . connected ) { throw new Error ( "Already connected" ) ; } return this . _bleDevice . connect ( ) ; } method returns { Promise } public disconnect ( ) { return this . _bleDevice . disconnect ( ) ; } method param { string } portName returns { Device | undefined } public getDeviceAtPort ( portName ) { const portId = this . _portMap [ portName ] ; if ( portId !== undefined ) { return this . _attachedDevices [ portId ] ; } else { return undefined ; } } method param { string } portName returns { Promise } public waitForDeviceAtPort ( portName ) { return new Promise ( ( resolve ) => { const existingDevice = this . getDeviceAtPort ( portName ) ; if ( existingDevice ) { return resolve ( existingDevice ) ; } this . _attachCallbacks . push ( ( device ) => { if ( device . portName === portName ) { resolve ( device ) ; return true ; } else { return false ; } } ) ; } ) ; } method returns { Device [ ] } public getDevices ( ) { return Object . values ( this . _attachedDevices ) ; } method param { number } deviceType returns { Device [ ] } public getDevicesByType ( deviceType ) { return this . getDevices ( ) . filter ( ( device ) => device . type === deviceType ) ; } method param { number } deviceType returns { Promise } public waitForDeviceByType ( deviceType ) { return new Promise ( ( resolve ) => { const existingDevices = this . getDevicesByType ( deviceType ) ; if ( existingDevices . length >= 1 ) { return resolve ( existingDevices [ 0 ] ) ; } this . _attachCallbacks . push ( ( device ) => { if ( device . type === deviceType ) { resolve ( device ) ; return true ; } else { return false ; } } ) ; } ) ; } public getPortNameForPortId ( portId ) { for ( const port of Object . keys ( this . _portMap ) ) { if ( this . _portMap [ port ] === portId ) { return port ; } } return ; } public isPortVirtual ( portId ) { return ( this . _virtualPorts . indexOf ( portId ) > - 1 ) ; } method param { number } delay returns { Promise } public sleep ( delay ) { return new Promise ( ( resolve ) => { global . setTimeout ( resolve , delay ) ; } ) ; } method param { Array < Promise < any > > } commands returns { Promise } public wait ( commands ) { return Promise . all ( commands ) ; } public send ( message , uuid ) { return Promise . resolve ( ) ; } public subscribe ( portId , deviceType , mode ) { } public unsubscribe ( portId , deviceType , mode ) { } public manuallyAttachDevice ( deviceType , portId ) { if ( ! this . _attachedDevices [ portId ] ) { debug ( `No device attached to portId ${ portId }, creating and attaching device type ${ deviceType }` ) ; const device = this . _createDevice ( deviceType , portId ) ; this . _attachDevice ( device ) ; return device ; } else { if ( this . _attachedDevices [ portId ] . type === deviceType ) { debug ( `Device of ${ deviceType } already attached to portId ${ portId }, returning existing device` ) ; return this . _attachedDevices [ portId ] ; } else { throw new Error ( `Already a different type of device attached to portId ${ portId }. Only use this method when you are certain what's attached.` ) ; } } } protected _attachDevice ( device ) { if ( this . _attachedDevices [ device . portId ] && this . _attachedDevices [ device . portId ] . type === device . type ) { return ; } this . _attachedDevices [ device . portId ] = device ; event param { Device } device this . emit ( "attach" , device ) ; debug ( `Attached device type ${ device . type } (${ Consts . DeviceTypeNames [ device . type ] }) on port ${ device . portName } (${ device . portId })` ) ; let i = this . _attachCallbacks . length ; while ( i -- ) { const callback = this . _attachCallbacks [ i ] ; if ( callback ( device ) ) { this . _attachCallbacks . splice ( i , 1 ) ; } } } protected _detachDevice ( device ) { delete this . _attachedDevices [ device . portId ] ; event param { Device } device this . emit ( "detach" , device ) ; debug ( `Detached device type ${ device . type } (${ Consts . DeviceTypeNames [ device . type ] }) on port ${ device . portName } (${ device . portId })` ) ; } protected _createDevice ( deviceType , portId ) { let constructor ; const deviceConstructors = { [ Consts . DeviceType . LIGHT ] : Light , [ Consts . DeviceType . TRAIN_MOTOR ] : TrainMotor , [ Consts . DeviceType . SIMPLE_MEDIUM_LINEAR_MOTOR ] : SimpleMediumLinearMotor , [ Consts . DeviceType . MOVE_HUB_MEDIUM_LINEAR_MOTOR ] : MoveHubMediumLinearMotor , [ Consts . DeviceType . MOTION_SENSOR ] : MotionSensor , [ Consts . DeviceType . TILT_SENSOR ] : TiltSensor , [ Consts . DeviceType . MOVE_HUB_TILT_SENSOR ] : MoveHubTiltSensor , [ Consts . DeviceType . PIEZO_BUZZER ] : PiezoBuzzer , [ Consts . DeviceType . TECHNIC_COLOR_SENSOR ] : TechnicColorSensor , [ Consts . DeviceType . TECHNIC_DISTANCE_SENSOR ] : TechnicDistanceSensor , [ Consts . DeviceType . TECHNIC_FORCE_SENSOR ] : TechnicForceSensor , [ Consts . DeviceType . TECHNIC_MEDIUM_HUB_TILT_SENSOR ] : TechnicMediumHubTiltSensor , [ Consts . DeviceType . TECHNIC_MEDIUM_HUB_GYRO_SENSOR ] : TechnicMediumHubGyroSensor , [ Consts . DeviceType . TECHNIC_MEDIUM_HUB_ACCELEROMETER ] : TechnicMediumHubAccelerometerSensor , [ Consts . DeviceType . MEDIUM_LINEAR_MOTOR ] : MediumLinearMotor , [ Consts . DeviceType . TECHNIC_SMALL_ANGULAR_MOTOR ] : TechnicSmallAngularMotor , [ Consts . DeviceType . TECHNIC_MEDIUM_ANGULAR_MOTOR ] : TechnicMediumAngularMotor , [ Consts . DeviceType . TECHNIC_LARGE_ANGULAR_MOTOR ] : TechnicLargeAngularMotor , [ Consts . DeviceType . TECHNIC_LARGE_LINEAR_MOTOR ] : TechnicLargeLinearMotor , [ Consts . DeviceType . TECHNIC_XLARGE_LINEAR_MOTOR ] : TechnicXLargeLinearMotor , [ Consts . DeviceType . COLOR_DISTANCE_SENSOR ] : ColorDistanceSensor , [ Consts . DeviceType . VOLTAGE_SENSOR ] : VoltageSensor , [ Consts . DeviceType . CURRENT_SENSOR ] : CurrentSensor , [ Consts . DeviceType . REMOTE_CONTROL_BUTTON ] : RemoteControlButton , [ Consts . DeviceType . HUB_LED ] : HubLED , [ Consts . DeviceType . DUPLO_TRAIN_BASE_COLOR_SENSOR ] : DuploTrainBaseColorSensor , [ Consts . DeviceType . DUPLO_TRAIN_BASE_MOTOR ] : DuploTrainBaseMotor , [ Consts . DeviceType . DUPLO_TRAIN_BASE_SPEAKER ] : DuploTrainBaseSpeaker , [ Consts . DeviceType . DUPLO_TRAIN_BASE_SPEEDOMETER ] : DuploTrainBaseSpeedometer , [ Consts . DeviceType . MARIO_ACCELEROMETER ] : MarioAccelerometer , [ Consts . DeviceType . MARIO_BARCODE_SENSOR ] : MarioBarcodeSensor , [ Consts . DeviceType . MARIO_PANTS_SENSOR ] : MarioPantsSensor , [ Consts . DeviceType . TECHNIC_MEDIUM_ANGULAR_MOTOR_GREY ] : TechnicMediumAngularMotor , [ Consts . DeviceType . TECHNIC_LARGE_ANGULAR_MOTOR_GREY ] : TechnicLargeAngularMotor , [ Consts . DeviceType . TECHNIC_3X3_COLOR_LIGHT_MATRIX ] : Technic3x3ColorLightMatrix , } ; constructor = deviceConstructors [ deviceType as Consts . DeviceType ] ; if ( constructor ) { return new constructor ( this , portId , undefined , deviceType ) ; } else { return new Device ( this , portId , undefined , deviceType ) ; } } protected _getDeviceByPortId ( portId ) { return this . _attachedDevices [ portId ] ; } }