Skip to content

Commit

Permalink
bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Guido Doumen committed Dec 19, 2024
1 parent 53ee080 commit c28f5cb
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 27 deletions.
45 changes: 33 additions & 12 deletions src/ble/base/interface.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import EventEmitter from "events";
import { DeviceSettings, InterfaceProps } from "../../types";
import { EventLogger } from "gd-eventlog";
import { BleBinding, BleInterfaceState, BlePeripheralAnnouncement, BlePeripheralInfo, BleRawPeripheral, BleScanProps, IBlePeripheral } from "../types";
import { BleBinding, BleDeviceSettings, BleInterfaceState, BlePeripheralAnnouncement, BlePeripheralInfo, BleProtocol, BleRawPeripheral, BleScanProps, IBlePeripheral } from "../types";
import { IBleInterface } from '../../ble/types';
import { InteruptableTask, TaskState } from "../../utils/task";
import { BlePeripheral } from "./peripheral";
import { beautifyUUID, parseUUID } from "../utils";
import { getPeripheralInfo, parseUUID } from "../utils";
import { InterfaceFactory } from "./types";
import { BleAdapterFactory } from "../factories";
import { TBleSensor } from "./sensor";

const BLE_DEFAULT_SCAN_TIMEOUT = 30*1000; // 30s
const BLE_EXPIRATION_TIMEOUT = 10*1000*60 // 10min
const BLE_DEFAULT_CONNECT_TIMEOUT = 30*1000; // 30s

Expand Down Expand Up @@ -136,7 +136,13 @@ export class BleInterface extends EventEmitter implements IBleInterface<BlePer
* @param {BleBinding} binding - The binding instance.
*/
setBinding(binding: BleBinding): void {

this.binding = binding

if (!this.isConnected()) {
this.autoConnect()
}

}

/**
Expand Down Expand Up @@ -278,11 +284,12 @@ export class BleInterface extends EventEmitter implements IBleInterface<BlePer


}
stopScan(): Promise<boolean> {
if (!this.isScanning()) return Promise.resolve(true);
async stopScan(): Promise<boolean> {
if (!this.isScanning()) return true;

this.logEvent({message:'stopping scan ...'})
this.scanTask.stop()
this.logEvent({message:'stopping scan ...', interface:'ble'})
const res = await this.scanTask.stop()
return (res===true)
}

onScanDone():DeviceSettings[] {
Expand Down Expand Up @@ -339,14 +346,20 @@ export class BleInterface extends EventEmitter implements IBleInterface<BlePer
}


createDeviceSetting(service:BlePeripheralAnnouncement):DeviceSettings {
const name = service.name
createDeviceSetting(service:BlePeripheralAnnouncement):BleDeviceSettings {
const {peripheral} = service

return {interface:BleInterface.INTERFACE_NAME, name}
// I found some scans (on Mac) where address was not set
if (peripheral.address===undefined || peripheral.address==='')
peripheral.address = peripheral.id || peripheral.name;

const protocol = this.getAdapterFactory().getProtocol(service.serviceUUIDs)
const {id,name,address} = getPeripheralInfo(peripheral)

return {interface:BleInterface.INTERFACE_NAME, protocol, id,name,address}
}



protected async reconnect() {
await this.disconnect()
await this.connect(true)
Expand Down Expand Up @@ -602,13 +615,17 @@ export class BleInterface extends EventEmitter implements IBleInterface<BlePer

protected emitDevice(service:BlePeripheralAnnouncement) {
const settings = this.createDeviceSetting(service)
this.logEvent({message:'device found',settings})
this.emit('device',settings,service)
}


protected buildDeviceSettings(matching:string[]=[]) {

return matching.map( (name)=> ({interface:BleInterface.INTERFACE_NAME, name}) )
return matching.map( (name)=> {
const announcement = this.services.find(s=>s.service.name===name)
return this.createDeviceSetting(announcement.service)
})
}


Expand Down Expand Up @@ -756,6 +773,10 @@ export class BleInterface extends EventEmitter implements IBleInterface<BlePer
// TODO
}

protected getAdapterFactory():BleAdapterFactory<TBleSensor> {
return BleAdapterFactory.getInstance('ble')
}




Expand Down
6 changes: 6 additions & 0 deletions src/ble/base/sensor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export class TBleSensor extends EventEmitter implements IBleSensor {
this.onDataHandler = this.onData.bind(this)
}

getDetectionPriority():number {
const C = this.constructor as typeof TBleSensor
return C['detectionPriority']??0

}

getProfile(): LegacyProfile {
const C = this.constructor as typeof TBleSensor
return C['profile']
Expand Down
55 changes: 47 additions & 8 deletions src/ble/factories/adapter-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@ import { DeviceProperties } from "../../types";
import { fullUUID, mapLegacyProfile } from "../utils";
import { BleDeviceData } from "../base/types";
import { TBleSensor } from "../base/sensor";
import { BleAdapterInfo, TBleAdapterFactory } from "./types";

export interface BleAdapterInfo<T extends TBleSensor> {
protocol: BleProtocol,
Adapter: typeof BleAdapter<BleDeviceData,T>
Sensor: typeof TBleSensor
}


export class BleAdapterFactory<T extends TBleSensor> {
export class BleAdapterFactory<T extends TBleSensor> implements TBleAdapterFactory<T> {
static readonly _instances:Record<string, BleAdapterFactory<any>> = {};

implementations: BleAdapterInfo<any>[]
Expand Down Expand Up @@ -143,7 +137,52 @@ export class BleAdapterFactory<T extends TBleSensor> {
return res;
}

getProtocol(services:string[]):BleProtocol {
const matching = this.getMatchingSensors(services)
if (!matching?.length) {
return;
}

if (matching.length===1) {
return matching[0].getProtocol()
}
matching.sort( (a,b) => b.getDetectionPriority()-a.getDetectionPriority())
return matching[0].getProtocol()
}

protected getMatchingSensors (services:string[], props:{ protocol?: BleProtocol, services?: string[] } = {}): TBleSensor[] {
let sensors;
const {protocol} = props;


// find matching Classes in the set of all registered Device Classes
const classes = this.getAllSupportedSensors()
sensors = this.getSensorsFromServices( classes, services)

if (protocol && sensors?.length>0) {
return sensors.filter( sensor => {

if (sensor.getProtocol()!==protocol)
return false;
return true;
})

}
return sensors
}

getSensorsFromServices(sensorTypes : (typeof TBleSensor)[],services :string | string[]) :TBleSensor[] {
if (!sensorTypes || !Array.isArray(sensorTypes) || sensorTypes.length === 0) {
return []
}

let serviceUUIDs = Array.isArray(services) ? services : [services];

const types = sensorTypes.map(SensorType=>new SensorType(null)).filter( sensor => sensor.isMatching(serviceUUIDs))
return types;

}




Expand Down
16 changes: 16 additions & 0 deletions src/ble/factories/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DeviceProperties } from "../../types";
import BleAdapter from "../base/adapter";
import { TBleSensor } from "../base/sensor";
import { BleDeviceData } from "../base/types";
import { BleDeviceSettings, BleProtocol } from "../types";

export interface TBleAdapterFactory<T extends TBleSensor> {
createInstance(settings:BleDeviceSettings,props?:DeviceProperties):BleAdapter<BleDeviceData,T>
removeInstance( query:{settings?:BleDeviceSettings, adapter?:BleAdapter<BleDeviceData,T>}):void
getProtocol(services:string[]):BleProtocol
}
export interface BleAdapterInfo<T extends TBleSensor> {
protocol: BleProtocol;
Adapter: typeof BleAdapter<BleDeviceData, T>;
Sensor: typeof TBleSensor;
}
1 change: 1 addition & 0 deletions src/ble/fm/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export default class BleFmAdapter extends BleAdapter<IndoorBikeData,BleFitnessMa
const after = this.capabilities.join(',')

if (before !== after) {
this.logEvent({message:'device capabilities updated', name:this.getSettings().name, interface:this.getSettings().interface,capabilities: this.capabilities})
this.emit('device-info', this.getSettings(), {capabilities:this.capabilities})
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/direct-connect/base/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,16 @@ export default class DirectConnectInterface extends EventEmitter implements IB
this.logEvent({message:'starting multicast DNS scan ..'})


this.getBinding().mdns.find( null,( service:MulticastDnsAnnouncement )=>{
this.addService( service )

} )
this.getBinding().mdns.find( {type:DC_TYPE},( service:MulticastDnsAnnouncement )=>{
this.addService( service )

} )


}
catch (err) {
this.logError(err, 'connect')
Expand Down Expand Up @@ -265,12 +271,13 @@ export default class DirectConnectInterface extends EventEmitter implements IB

}
async stopScan(): Promise<boolean> {
if (!this.isScanning()) return Promise.resolve(true);
if (!this.isScanning())
return true

this.logEvent({message:'stopping scan ...'})
this.logEvent({message:'stopping scan ...', interface:'wifi'})
const res = await this.scanTask.stop()
delete this.scanTask
return res
return (res===true)
}

onScanDone():DeviceSettings[] {
Expand Down Expand Up @@ -367,8 +374,9 @@ export default class DirectConnectInterface extends EventEmitter implements IB
}
else {
this.logEvent({message:'device announced',device:service.name, announcement:service})

this.services.push( {ts:Date.now(),service})
if (service.type!==DC_TYPE && service.serviceUUIDs?.length===0)
return;

this.emitDevice(service)
this.matching?.push(service.name)
Expand Down
3 changes: 2 additions & 1 deletion src/direct-connect/bindings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ export interface DirectConnectBinding {
type KeyValue = { [key: string]: any }

export interface BrowserConfig {
type : string
type? : string
name? : string
protocol? : 'tcp' | 'udp'
subtypes? : string[]
txt? : KeyValue
}

export interface MulticastDnsAnnouncement extends PeripheralAnnouncement{
type : string
address : string
protocol? : 'tcp' | 'udp'
port : number
Expand Down
2 changes: 0 additions & 2 deletions src/factories/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export default class AdapterFactory {

const ifaceName = typeof settings.interface ==='string' ? settings.interface : (settings.interface as IncyclistInterface).getName()

console.log(`creating adapter for ${ifaceName}`)
let adapter;
switch (ifaceName) {
case INTERFACE.SERIAL:
Expand All @@ -57,7 +56,6 @@ export default class AdapterFactory {
case INTERFACE.DC:
{
const factory = BleAdapterFactory.getInstance('wifi')
console.log('creating wifi adapter for direct connect',factory)
adapter = BleAdapterFactory.getInstance('wifi').createInstance(settings as BleDeviceSettings,props)
}
break;
Expand Down

0 comments on commit c28f5cb

Please sign in to comment.