Skip to content

Commit

Permalink
fix(bluetooth-classic): request info only on current instance
Browse files Browse the repository at this point in the history
Instead of querying the info from a device across all instances at once,
this is now just done when the instance was also responsible for the
query.
  • Loading branch information
mKeRix committed Feb 28, 2020
1 parent d463dbd commit 9ae5cca
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { ClusterModule } from '../../cluster/cluster.module';
import { EntitiesService } from '../../entities/entities.service';
import { ClusterService } from '../../cluster/cluster.service';
import { ScheduleModule } from '@nestjs/schedule';
import * as util from 'util';
import {
NEW_RSSI_CHANNEL,
REQUEST_RSSI_CHANNEL
Expand All @@ -20,6 +19,7 @@ import { Switch } from '../../entities/switch';
import { BluetoothClassicConfig } from './bluetooth-classic.config';
import c from 'config';
import { ConfigService } from '../../config/config.service';
import { Device } from './device';

jest.mock('../room-presence/room-presence-distance.sensor');
jest.mock('kalmanjs', () => {
Expand Down Expand Up @@ -215,9 +215,11 @@ Requesting information ...
const handleRssiMock = jest
.spyOn(service, 'handleNewRssi')
.mockImplementation(() => undefined);

const address = '77:50:fb:4d:ab:70';
const expectedEvent = new NewRssiEvent('test-instance', address, 0);
const device = new Device(address, 'Test Device');
jest.spyOn(service, 'inquireDeviceInfo').mockResolvedValue(device);

const expectedEvent = new NewRssiEvent('test-instance', device, 0);

await service.handleRssiRequest(address);
expect(clusterService.publish).toHaveBeenCalledWith(
Expand Down Expand Up @@ -275,7 +277,10 @@ Requesting information ...
config.minRssi = -10;

const address = '77:50:fb:4d:ab:70';
const expectedEvent = new NewRssiEvent('test-instance', address, -11, true);
const device = new Device(address, 'Test Device');
jest.spyOn(service, 'inquireDeviceInfo').mockResolvedValue(device);

const expectedEvent = new NewRssiEvent('test-instance', device, -11, true);

await service.handleRssiRequest(address);
expect(handleRssiMock).toHaveBeenCalledWith(expectedEvent);
Expand All @@ -285,6 +290,42 @@ Requesting information ...
);
});

it('should gather the device info for previously unkown addresses', async () => {
jest.spyOn(service, 'shouldInquire').mockReturnValue(true);
jest.spyOn(service, 'inquireRssi').mockResolvedValue(0);
jest.spyOn(service, 'handleNewRssi').mockImplementation(() => undefined);

const address = '77:50:fb:4d:ab:70';
const device = new Device(address, 'Test Device');
const infoSpy = jest
.spyOn(service, 'inquireDeviceInfo')
.mockResolvedValue(device);

await service.handleRssiRequest(address);

expect(infoSpy).toHaveBeenCalledWith('77:50:fb:4d:ab:70');
});

it('should re-use already gathered device information', async () => {
jest.spyOn(service, 'shouldInquire').mockReturnValue(true);
jest.spyOn(service, 'inquireRssi').mockResolvedValue(0);
const handleSpy = jest
.spyOn(service, 'handleNewRssi')
.mockImplementation(() => undefined);

const address = '77:50:fb:4d:ab:70';
const device = new Device(address, 'Test Device');
const infoSpy = jest
.spyOn(service, 'inquireDeviceInfo')
.mockResolvedValue(device);

await service.handleRssiRequest(address);
await service.handleRssiRequest(address);

expect(infoSpy).toHaveBeenCalledTimes(1);
expect(handleSpy.mock.calls[1][0].device).toEqual(device);
});

it('should ignore RSSI requests of inquiries are disabled', () => {
jest.spyOn(service, 'shouldInquire').mockReturnValue(false);
const handleRssiMock = jest
Expand All @@ -307,7 +348,11 @@ Requesting information ...
});
jest.useFakeTimers();

const event = new NewRssiEvent('test-instance', '10:36:cf:ca:9a:18', -10);
const event = new NewRssiEvent(
'test-instance',
new Device('10:36:cf:ca:9a:18', 'Test Device'),
-10
);
await service.handleNewRssi(event);

expect(entitiesService.add).toHaveBeenCalledWith(
Expand Down Expand Up @@ -473,7 +518,10 @@ Requesting information ...
.mockReturnValue(-5.2);

const address = 'ab:cd:01:23:00:70';
const expectedEvent = new NewRssiEvent('test-instance', address, -5.2);
const device = new Device(address, 'Test Device');
jest.spyOn(service, 'inquireDeviceInfo').mockResolvedValue(device);

const expectedEvent = new NewRssiEvent('test-instance', device, -5.2);

await service.handleRssiRequest(address);
expect(filterRssiMock).toHaveBeenCalled();
Expand Down
34 changes: 21 additions & 13 deletions src/integrations/bluetooth-classic/bluetooth-classic.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 1)
private readonly config: BluetoothClassicConfig;
private rotationOffset = 0;
private inquiriesSwitch: Switch;
private deviceMap = new Map<string, Device>();
private logger: Logger;

constructor(
Expand Down Expand Up @@ -86,9 +87,18 @@ export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 1)

if (rssi !== undefined) {
rssi = _.round(this.filterRssi(address, rssi), 1);

let device: Device;
if (this.deviceMap.has(address)) {
device = this.deviceMap.get(address);
} else {
device = await this.inquireDeviceInfo(address);
this.deviceMap.set(address, device);
}

const event = new NewRssiEvent(
this.configService.get('global').instanceName,
address,
device,
rssi,
rssi < this.config.minRssi
);
Expand All @@ -107,15 +117,15 @@ export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 1)
*/
async handleNewRssi(event: NewRssiEvent): Promise<void> {
this.logger.debug(
`Received RSSI of ${event.rssi} for ${event.address} from ${event.instanceName}`
`Received RSSI of ${event.rssi} for ${event.device.address} from ${event.instanceName}`
);

const sensorId = makeId(`bluetooth-classic ${event.address}`);
const sensorId = makeId(`bluetooth-classic ${event.device.address}`);
let sensor: RoomPresenceDistanceSensor;
if (this.entitiesService.has(sensorId)) {
sensor = this.entitiesService.get(sensorId) as RoomPresenceDistanceSensor;
} else {
sensor = await this.createSensor(sensorId, event.address);
sensor = await this.createSensor(sensorId, event.device);
}

sensor.timeout = this.calculateCurrentTimeout();
Expand Down Expand Up @@ -298,25 +308,23 @@ export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 1)
* Creates and registers a new room presence sensor.
*
* @param sensorId - Entity ID for the new sensor
* @param address - Bluetooth MAC address of the matching device
* @param device - Device information of the peripheral
* @returns Registered sensor
*/
protected async createSensor(
sensorId: string,
address: string
device: Device
): Promise<RoomPresenceDistanceSensor> {
const deviceInfo = await this.inquireDeviceInfo(address);

const customizations: Array<EntityCustomization<any>> = [
{
for: SensorConfig,
overrides: {
icon: 'mdi:bluetooth',
device: {
identifiers: deviceInfo.address,
name: deviceInfo.name,
manufacturer: deviceInfo.manufacturer,
connections: [['mac', deviceInfo.address]],
identifiers: device.address,
name: device.name,
manufacturer: device.manufacturer,
connections: [['mac', device.address]],
viaDevice: DISTRIBUTED_DEVICE_ID
}
}
Expand All @@ -325,7 +333,7 @@ export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 1)
const sensor = this.entitiesService.add(
new RoomPresenceDistanceSensor(
sensorId,
`${deviceInfo.name} Room Presence`,
`${device.name} Room Presence`,
0
),
customizations
Expand Down
8 changes: 5 additions & 3 deletions src/integrations/bluetooth-classic/new-rssi.event.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Device } from './device';

export class NewRssiEvent {
instanceName: string;
address: string;
device: Device;
rssi: number;
outOfRange: boolean;

constructor(
instanceName: string,
address: string,
device: Device,
rssi: number,
outOfRange = false
) {
this.instanceName = instanceName;
this.address = address;
this.device = device;
this.rssi = rssi;
this.outOfRange = outOfRange;
}
Expand Down

0 comments on commit 9ae5cca

Please sign in to comment.