Skip to content

Commit

Permalink
feat(bluetooth-low-energy): share discovered apps with cluster
Browse files Browse the repository at this point in the history
  • Loading branch information
mKeRix committed Nov 1, 2020
1 parent a7b61aa commit 188e76c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 5 deletions.
Expand Up @@ -19,6 +19,7 @@ import { Peripheral } from '@abandonware/noble';
import { ConfigService } from '../../config/config.service';
import { Test, TestingModule } from '@nestjs/testing';
import {
APP_DISCOVERY_CHANNEL,
BluetoothLowEnergyService,
NEW_DISTANCE_CHANNEL,
} from './bluetooth-low-energy.service';
Expand Down Expand Up @@ -152,6 +153,14 @@ describe('BluetoothLowEnergyService', () => {
expect.any(Function)
);
expect(clusterService.subscribe).toHaveBeenCalledWith(NEW_DISTANCE_CHANNEL);

expect(clusterService.on).toHaveBeenCalledWith(
APP_DISCOVERY_CHANNEL,
expect.any(Function)
);
expect(clusterService.subscribe).toHaveBeenCalledWith(
APP_DISCOVERY_CHANNEL
);
});

it('should detect iBeacons based on their manufacturer data', () => {
Expand Down Expand Up @@ -951,6 +960,34 @@ describe('BluetoothLowEnergyService', () => {
expect(discoverSpy).toHaveBeenCalledTimes(1);
});

it('should publish discovered companion app IDs to the cluster', async () => {
jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
jest.spyOn(service, 'isWhitelistEnabled').mockReturnValue(true);
jest.spyOn(service, 'isOnWhitelist').mockReturnValue(true);
jest.spyOn(service, 'discoverCompanionAppId').mockResolvedValue('app-id');

await service.handleDiscovery({
id: 'abcd1234',
rssi: -50,
connectable: true,
advertisement: {
localName: 'Test Beacon',
txPowerLevel: -72,
manufacturerData: APPLE_MANUFACTURER_DATA,
},
} as Peripheral);

expect(clusterService.publish).toHaveBeenCalledWith(
APP_DISCOVERY_CHANNEL,
{
tagId: 'abcd1234',
appId: 'app-id',
}
);
});

it('should temporarily blacklist devices that time out from discovery attempts', async () => {
jest.useFakeTimers('modern');
jest
Expand Down
Expand Up @@ -26,8 +26,11 @@ import { BluetoothLowEnergyPresenceSensor } from './bluetooth-low-energy-presenc
import { BluetoothService } from '../bluetooth/bluetooth.service';

export const NEW_DISTANCE_CHANNEL = 'bluetooth-low-energy.new-distance';
export const APP_DISCOVERY_CHANNEL = 'bluetooth-low-energy.app-discovery';
const APPLE_ADVERTISEMENT_ID = Buffer.from([0x4c, 0x00, 0x10]);

type AppDiscoveryEvent = { tagId: string; appId: string };

@Injectable() // parameters determined experimentally
export class BluetoothLowEnergyService
extends KalmanFilterable(Object, 0.8, 15)
Expand Down Expand Up @@ -74,6 +77,12 @@ export class BluetoothLowEnergyService
this.handleNewDistance.bind(this)
);
this.clusterService.subscribe(NEW_DISTANCE_CHANNEL);

this.clusterService.on(
APP_DISCOVERY_CHANNEL,
this.handleAppDiscovery.bind(this)
);
this.clusterService.subscribe(APP_DISCOVERY_CHANNEL);
}

/**
Expand Down Expand Up @@ -410,13 +419,19 @@ export class BluetoothLowEnergyService
try {
this.logger.log(`Attempting app discovery for tag ${tag.id}`);
const appId = await this.discoverCompanionAppId(tag);
this.companionAppTags.set(tag.id, appId);

if (appId) {
this.logger.log(
`Discovered companion app with ID ${appId} for tag ${tag.id}`
);
}

const event = {
tagId: tag.id,
appId: appId,
} as AppDiscoveryEvent;
this.clusterService.publish(APP_DISCOVERY_CHANNEL, event);
this.handleAppDiscovery(event);
} catch (e) {
if (e.message === 'timed out') {
this.logger.debug(
Expand All @@ -436,13 +451,28 @@ export class BluetoothLowEnergyService
this.companionAppTags.delete(tag.id);
}
}
}

const appId = this.companionAppTags.get(tag.id);
if (appId != null) {
tag.id = appId;
}
const appId = this.companionAppTags.get(tag.id);
if (appId != null) {
tag.id = appId;
}

return tag;
}

/**
* Adds discovered app information to the local cache.
* Does not override already existing values to null.
*
* @param event - Discovered information
*/
protected handleAppDiscovery(event: AppDiscoveryEvent): void {
const oldId = this.companionAppTags.get(event.tagId);

if (!(oldId != null && event.appId == null)) {
this.companionAppTags.set(event.tagId, event.appId);
this.companionAppBlacklist.delete(event.tagId);
}
}
}

0 comments on commit 188e76c

Please sign in to comment.