Skip to content

Commit

Permalink
feat(bluetooth-low-energy): removed individual distance sensors
Browse files Browse the repository at this point in the history
Each BLE peripheral will now only receive a single, distributed entity.
See discussion in #102 for more info.
  • Loading branch information
mKeRix committed Jan 27, 2020
1 parent 649d207 commit af9e639
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 94 deletions.
Expand Up @@ -146,9 +146,6 @@ describe('BluetoothLowEnergyService', () => {
});

it('should publish iBeacon distance changes', () => {
const sensor = new Sensor('testid', 'Test');
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);
const handleDistanceSpy = jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
Expand All @@ -172,7 +169,6 @@ describe('BluetoothLowEnergyService', () => {
'Test Beacon',
0.7
);
expect(sensor.state).toBe(0.7);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
expect(clusterService.publish).toHaveBeenCalledWith(
NEW_DISTANCE_CHANNEL,
Expand All @@ -181,9 +177,6 @@ describe('BluetoothLowEnergyService', () => {
});

it('should not process iBeacon data if disabled in the config', () => {
const sensor = new Sensor('testid', 'Test');
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);
const handleDistanceSpy = jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
Expand All @@ -205,7 +198,6 @@ describe('BluetoothLowEnergyService', () => {
'Test Beacon',
1
);
expect(sensor.state).toBe(1);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
expect(clusterService.publish).toHaveBeenCalledWith(
NEW_DISTANCE_CHANNEL,
Expand All @@ -214,9 +206,6 @@ describe('BluetoothLowEnergyService', () => {
});

it('should publish distance changes for normal BLE devices', () => {
const sensor = new Sensor('testid', 'Test');
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);
const handleDistanceSpy = jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
Expand All @@ -235,7 +224,6 @@ describe('BluetoothLowEnergyService', () => {
'Test BLE Device',
10.5
);
expect(sensor.state).toBe(10.5);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
expect(clusterService.publish).toHaveBeenCalledWith(
NEW_DISTANCE_CHANNEL,
Expand All @@ -244,9 +232,6 @@ describe('BluetoothLowEnergyService', () => {
});

it('should apply tag distance override if it exists', () => {
const sensor = new Sensor('testid', 'Test');
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);
const handleDistanceSpy = jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
Expand All @@ -270,7 +255,6 @@ describe('BluetoothLowEnergyService', () => {
'Test BLE Device',
1.1
);
expect(sensor.state).toBe(1.1);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
expect(clusterService.publish).toHaveBeenCalledWith(
NEW_DISTANCE_CHANNEL,
Expand All @@ -287,7 +271,6 @@ describe('BluetoothLowEnergyService', () => {

expectedEvent.tagId = 'defg';
expectedEvent.distance = 10.5;
expect(sensor.state).toBe(10.5);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
expect(clusterService.publish).toHaveBeenCalledWith(
NEW_DISTANCE_CHANNEL,
Expand All @@ -296,10 +279,7 @@ describe('BluetoothLowEnergyService', () => {
});

it('should apply a tag name override if it exists', () => {
const sensor = new Sensor('testid', 'Test');
entitiesService.has.mockReturnValue(false);
entitiesService.add.mockReturnValue(sensor);
jest
const handleDistanceSpy = jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
mockConfig.tagOverrides = {
Expand All @@ -316,40 +296,13 @@ describe('BluetoothLowEnergyService', () => {
}
} as Peripheral);

expect(entitiesService.add).toHaveBeenCalledWith(
expect(handleDistanceSpy).toHaveBeenCalledWith(
expect.objectContaining({
name: expect.stringContaining('better name')
}),
expect.any(Array)
tagName: 'better name'
})
);
});

it('should create a new distance sensor if there is not a matching one yet', () => {
const sensor = new Sensor('new', 'New');
entitiesService.has.mockReturnValue(false);
entitiesService.add.mockReturnValue(sensor);
jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);

service.handleDiscovery({
id: 'abcd',
rssi: -60,
advertisement: {
localName: 'Test BLE Device'
}
} as Peripheral);

expect(entitiesService.add).toHaveBeenCalledWith(
expect.objectContaining({
id: 'ble-abcd',
name: 'Distance test-instance - Test BLE Device'
}),
expect.any(Array)
);
expect(sensor.state).toBe(1.1);
});

it('should not publish state changes for devices that are not on the whitelist', () => {
jest.spyOn(service, 'isOnWhitelist').mockReturnValue(false);

Expand Down Expand Up @@ -382,10 +335,7 @@ describe('BluetoothLowEnergyService', () => {
});

it('should filter the measured RSSI of the peripherals', () => {
const sensor = new Sensor('testid', 'Test');
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);
jest
const handleDistanceSpy = jest
.spyOn(service, 'handleNewDistance')
.mockImplementation(() => undefined);
const filterSpy = jest.spyOn(service, 'filterRssi').mockReturnValue(-50);
Expand All @@ -399,7 +349,11 @@ describe('BluetoothLowEnergyService', () => {
} as Peripheral);

expect(filterSpy).toHaveBeenCalledWith('12:ab:cd:12:cd', -45);
expect(sensor.state).toBe(0.2);
expect(handleDistanceSpy).toHaveBeenCalledWith(
expect.objectContaining({
distance: 0.2
})
);
});

it('should reuse existing Kalman filters for the same id', () => {
Expand Down
Expand Up @@ -7,11 +7,9 @@ import noble, { Peripheral } from '@abandonware/noble';
import * as _ from 'lodash';
import slugify from 'slugify';
import { EntitiesService } from '../../entities/entities.service';
import { Sensor } from '../../entities/sensor.entity';
import { IBeacon } from './i-beacon';
import { Tag } from './tag';
import { ConfigService } from '../../config/config.service';
import { Entity } from '../../entities/entity.entity';
import { BluetoothLowEnergyConfig } from './bluetooth-low-energy.config';
import { ClusterService } from '../../cluster/cluster.service';
import { NewDistanceEvent } from './new-distance.event';
Expand Down Expand Up @@ -74,15 +72,6 @@ export class BluetoothLowEnergyService
tag = this.applyOverrides(tag);
tag.rssi = this.filterRssi(tag.id, tag.rssi);

const sensorId = slugify(`ble ${_.lowerCase(tag.id)}`);
let sensor: Entity;
if (this.entitiesService.has(sensorId)) {
sensor = this.entitiesService.get(sensorId);
} else {
sensor = this.createDistanceSensor(sensorId, tag.name);
}
sensor.state = tag.distance;

const globalSettings = this.configService.get('global');
const event = new NewDistanceEvent(
globalSettings.instanceName,
Expand Down Expand Up @@ -157,33 +146,6 @@ export class BluetoothLowEnergyService
return this.kalmanFilter(rssi, tagId);
}

/**
* Creates and registers a new distance sensor (this machine <> peripheral).
*
* @param sensorId - Id that the sensor should receive
* @param deviceName - Name of the BLE peripheral
* @returns Registered sensor
*/
protected createDistanceSensor(sensorId: string, deviceName: string): Sensor {
const globalSettings = this.configService.get('global');

const sensorName = `Distance ${globalSettings.instanceName} - ${deviceName}`;
const customizations: Array<EntityCustomization<any>> = [
{
for: SensorConfig,
overrides: {
icon: 'mdi:bluetooth',
unitOfMeasurement: 'm'
}
}
];

return this.entitiesService.add(
new Sensor(sensorId, sensorName),
customizations
) as Sensor;
}

/**
* Creates and registers a new room presence sensor.
*
Expand Down

0 comments on commit af9e639

Please sign in to comment.