Skip to content

Commit

Permalink
feat(bluetooth-low-energy): add RSSI and measuredPower to entity
Browse files Browse the repository at this point in the history
Tuning BLE values is tricky if the measured RSSI and the measuredPower
used for calculation are not visible anywhere. Putting them into the
attributes would cause a lot of data to be constantly updated in the
other integrations, so now they are just available in the API as an
additional field of the entity.

Closes #140, #177 and #203
  • Loading branch information
mKeRix committed May 31, 2020
1 parent be02c10 commit ec48507
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 11 deletions.
@@ -0,0 +1,29 @@
import { RoomPresenceDistanceSensor } from '../room-presence/room-presence-distance.sensor';

class BluetoothLowEnergyMeasurement {
rssi: number;
measuredPower: number;

constructor(rssi: number, measuredPower: number) {
this.rssi = rssi;
this.measuredPower = measuredPower;
}
}

export class BluetoothLowEnergyPresenceSensor extends RoomPresenceDistanceSensor {
measuredValues: { [instance: string]: BluetoothLowEnergyMeasurement } = {};

handleNewMeasurement(
instanceName: string,
rssi: number,
measuredPower: number,
distance: number,
outOfRange: boolean
): void {
this.measuredValues[instanceName] = new BluetoothLowEnergyMeasurement(
rssi,
measuredPower
);
this.handleNewDistance(instanceName, distance, outOfRange);
}
}
Expand Up @@ -33,7 +33,7 @@ import { BluetoothLowEnergyConfig } from './bluetooth-low-energy.config';
import { Sensor } from '../../entities/sensor';
import c from 'config';
import { NewDistanceEvent } from './new-distance.event';
import { RoomPresenceDistanceSensor } from '../room-presence/room-presence-distance.sensor';
import { BluetoothLowEnergyPresenceSensor } from './bluetooth-low-energy-presence.sensor';
import KalmanFilter from 'kalmanjs';
import { DeviceTracker } from '../../entities/device-tracker';
import * as util from 'util';
Expand Down Expand Up @@ -188,6 +188,8 @@ describe('BluetoothLowEnergyService', () => {
'test-instance',
'2f234454cf6d4a0fadf2f4911ba9ffa6-1-2',
'Test Beacon',
-50,
-52,
0.7
);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
Expand Down Expand Up @@ -219,6 +221,8 @@ describe('BluetoothLowEnergyService', () => {
'test-instance',
'abcd1234',
'Test Beacon',
-59,
-59,
1
);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
Expand Down Expand Up @@ -247,6 +251,8 @@ describe('BluetoothLowEnergyService', () => {
'test-instance',
'123-123',
'Test BLE Device',
-81,
-59,
10.5
);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
Expand Down Expand Up @@ -359,6 +365,8 @@ describe('BluetoothLowEnergyService', () => {
'test-instance',
'abcd',
'Test BLE Device',
-81,
-80,
1.1
);
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
Expand All @@ -377,6 +385,7 @@ describe('BluetoothLowEnergyService', () => {

expectedEvent.tagId = 'defg';
expectedEvent.distance = 10.5;
expectedEvent.measuredPower = -59;
expect(handleDistanceSpy).toHaveBeenCalledWith(expectedEvent);
expect(clusterService.publish).toHaveBeenCalledWith(
NEW_DISTANCE_CHANNEL,
Expand Down Expand Up @@ -658,27 +667,27 @@ describe('BluetoothLowEnergyService', () => {
});

it('should pass distance information to existing room presence sensors', () => {
const sensor = new RoomPresenceDistanceSensor('test', 'Test', 0);
const sensor = new BluetoothLowEnergyPresenceSensor('test', 'Test', 0);
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);
const sensorHandleSpy = jest.spyOn(sensor, 'handleNewDistance');

service.handleNewDistance(
new NewDistanceEvent('test-instance', 'test', 'Test', 2)
new NewDistanceEvent('test-instance', 'test', 'Test', -80, -50, 2)
);

expect(sensorHandleSpy).toHaveBeenCalledWith('test-instance', 2, false);
});

it('should add new room presence sensor if no matching ones exist yet', () => {
const sensor = new RoomPresenceDistanceSensor('test', 'Test', 0);
const sensor = new BluetoothLowEnergyPresenceSensor('test', 'Test', 0);
entitiesService.has.mockReturnValue(false);
entitiesService.add.mockReturnValue(sensor);
mockConfig.timeout = 20;
const sensorHandleSpy = jest.spyOn(sensor, 'handleNewDistance');

service.handleNewDistance(
new NewDistanceEvent('test-instance', 'new', 'New Tag', 1.3)
new NewDistanceEvent('test-instance', 'new', 'New Tag', -80, -50, 1.3)
);

expect(entitiesService.add).toHaveBeenCalledWith(
Expand All @@ -699,6 +708,31 @@ describe('BluetoothLowEnergyService', () => {
expect(sensorHandleSpy).toHaveBeenCalledWith('test-instance', 1.3, false);
});

it('should update the sensor RSSI and measuredPower information', () => {
const sensor = new BluetoothLowEnergyPresenceSensor('test', 'Test', 0);
entitiesService.has.mockReturnValue(true);
entitiesService.get.mockReturnValue(sensor);

service.handleNewDistance(
new NewDistanceEvent('test-instance', 'test', 'Test', -80, -50, 2)
);

expect(sensor.measuredValues['test-instance'].rssi).toBe(-80);
expect(sensor.measuredValues['test-instance'].measuredPower).toBe(-50);

service.handleNewDistance(
new NewDistanceEvent('test-instance-2', 'test', 'Test', -40, -45, 2)
);
service.handleNewDistance(
new NewDistanceEvent('test-instance', 'test', 'Test', -70, -50, 2)
);

expect(sensor.measuredValues['test-instance-2'].rssi).toBe(-40);
expect(sensor.measuredValues['test-instance-2'].measuredPower).toBe(-45);
expect(sensor.measuredValues['test-instance'].rssi).toBe(-70);
expect(sensor.measuredValues['test-instance'].measuredPower).toBe(-50);
});

it('should log the id of new peripherals that are found', () => {
mockConfig.processIBeacon = true;
jest.spyOn(service, 'isOnWhitelist').mockReturnValue(false);
Expand Down
Expand Up @@ -22,6 +22,7 @@ import { DISTRIBUTED_DEVICE_ID } from '../home-assistant/home-assistant.const';
import * as _ from 'lodash';
import { DeviceTracker } from '../../entities/device-tracker';
import { RoomPresenceDeviceTrackerProxyHandler } from '../room-presence/room-presence-device-tracker.proxy';
import { BluetoothLowEnergyPresenceSensor } from './bluetooth-low-energy-presence.sensor';

export const NEW_DISTANCE_CHANNEL = 'bluetooth-low-energy.new-distance';

Expand Down Expand Up @@ -105,6 +106,8 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15)
globalSettings.instanceName,
tag.id,
tag.name,
tag.rssi,
tag.measuredPower,
tag.distance,
tag.distance > this.config.maxDistance
);
Expand All @@ -127,9 +130,11 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15)
*/
handleNewDistance(event: NewDistanceEvent): void {
const sensorId = makeId(`ble ${event.tagId}`);
let sensor: RoomPresenceDistanceSensor;
let sensor: BluetoothLowEnergyPresenceSensor;
if (this.entitiesService.has(sensorId)) {
sensor = this.entitiesService.get(sensorId) as RoomPresenceDistanceSensor;
sensor = this.entitiesService.get(
sensorId
) as BluetoothLowEnergyPresenceSensor;
} else {
sensor = this.createRoomPresenceSensor(
sensorId,
Expand All @@ -138,8 +143,10 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15)
);
}

sensor.handleNewDistance(
sensor.handleNewMeasurement(
event.instanceName,
event.rssi,
event.measuredPower,
event.distance,
event.outOfRange
);
Expand Down Expand Up @@ -236,7 +243,7 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15)
sensorId: string,
deviceId: string,
deviceName: string
): RoomPresenceDistanceSensor {
): BluetoothLowEnergyPresenceSensor {
const deviceTracker = this.createDeviceTracker(
makeId(`${sensorId}-tracker`),
deviceName
Expand All @@ -256,7 +263,7 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15)
},
},
];
const rawSensor = new RoomPresenceDistanceSensor(
const rawSensor = new BluetoothLowEnergyPresenceSensor(
sensorId,
sensorName,
this.config.timeout
Expand All @@ -268,7 +275,7 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15)
const sensor = this.entitiesService.add(
proxiedSensor,
customizations
) as RoomPresenceDistanceSensor;
) as BluetoothLowEnergyPresenceSensor;

const interval = setInterval(
sensor.updateState.bind(sensor),
Expand Down
6 changes: 6 additions & 0 deletions src/integrations/bluetooth-low-energy/new-distance.event.ts
Expand Up @@ -3,19 +3,25 @@ export class NewDistanceEvent {
instanceName: string,
tagId: string,
tagName: string,
rssi: number,
measuredPower: number,
distance: number,
outOfRange = false
) {
this.instanceName = instanceName;
this.tagId = tagId;
this.tagName = tagName;
this.rssi = rssi;
this.measuredPower = measuredPower;
this.distance = distance;
this.outOfRange = outOfRange;
}

instanceName: string;
tagId: string;
tagName: string;
rssi: number;
measuredPower: number;
distance: number;
outOfRange: boolean;
}

0 comments on commit ec48507

Please sign in to comment.