Skip to content

Commit

Permalink
feat(bluetooth-classic): add name override option
Browse files Browse the repository at this point in the history
Especially nice for devices that don't provide a friendly name.
Partially fulfills the request in #596.
  • Loading branch information
mKeRix committed Apr 11, 2021
1 parent 4950717 commit d0c5c52
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 9 deletions.
8 changes: 5 additions & 3 deletions docs/integrations/bluetooth-classic.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ Try to pair your Apple Watch to a Bluetooth device such as headphones/speakers f

The entity overrides object can be considered as a map with the device MAC as key and an object with some of the following settings as value.

| Name | Type | Default | Description |
| ---- | ------ | ------- | ------------------------------------------------------------ |
| `id` | String | | Changes the ID of the device entities. Useful to hide device addresses from publicly shared home automation configurations. |
| Name | Type | Default | Description |
| ------ | ------ | ------- | ------------------------------------------------------------ |
| `id` | String | | Changes the ID of the device entities. Useful to hide device addresses from publicly shared home automation configurations. |
| `name` | String | | Changes the friendly name for the device, which is sent to the home automation software for easier identification. |

::: details Simple Example Config

Expand Down Expand Up @@ -134,6 +135,7 @@ bluetoothClassic:
entityOverrides:
'08:05:90:ed:3b:60':
id: my-phone
name: My Phone
```

:::
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const MAC_ERROR = '{#label} does not match the required MAC address format';
class BluetoothClassicEntityOverride {
@(jf.string().optional())
id?: string;
@(jf.string().optional())
name?: string;
}

export class BluetoothClassicConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ import { DeviceTrackerConfig } from '../home-assistant/device-tracker-config';
import * as util from 'util';

jest.mock('mdns', () => ({}), { virtual: true });
jest.mock('../../integration-support/room-presence/room-presence-distance.sensor');
jest.mock(
'../../integration-support/room-presence/room-presence-distance.sensor'
);
jest.mock('kalmanjs', () => {
return jest.fn().mockImplementation(() => {
return {
Expand Down Expand Up @@ -87,7 +89,7 @@ describe('BluetoothClassicService', () => {
timeoutCycles: 2,
preserveState: false,
inquireFromStart: true,
entityOverrides: {}
entityOverrides: {},
};
const configService = {
get: jest.fn().mockImplementation((key: string) => {
Expand Down Expand Up @@ -479,7 +481,7 @@ describe('BluetoothClassicService', () => {
it('should register entities with overridden ID if available', async () => {
const deviceId = '10:36:cf:ca:9a:27';
const overriddenId = 'new-id';
config.entityOverrides[deviceId] = { id: overriddenId }
config.entityOverrides[deviceId] = { id: overriddenId };

entitiesService.has.mockReturnValue(false);
entitiesService.add.mockImplementation((entity) => entity);
Expand Down Expand Up @@ -519,6 +521,52 @@ describe('BluetoothClassicService', () => {
);
});

it('should register entities with overridden name if available', async () => {
const deviceId = '10:36:cf:ca:9a:27';
const overriddenName = 'New Name';
config.entityOverrides[deviceId] = { name: overriddenName };

entitiesService.has.mockReturnValue(false);
entitiesService.add.mockImplementation((entity) => entity);
clusterService.nodes.mockReturnValue({
abcd: { channels: [NEW_RSSI_CHANNEL] },
});
bluetoothService.inquireClassicDeviceInfo.mockResolvedValue({
address: deviceId,
name: 'Test iPhone',
});
jest.useFakeTimers();

const event = new NewRssiEvent(
'test-instance',
new Device(deviceId, 'Test iPhone'),
-10
);
await service.handleNewRssi(event);

expect(entitiesService.add).toHaveBeenCalledWith(
expect.objectContaining({
id: 'bluetooth-classic-10-36-cf-ca-9a-27-tracker',
name: 'New Name Tracker',
}),
[
{
for: DeviceTrackerConfig,
overrides: {
sourceType: 'bluetooth',
device: {
identifiers: deviceId,
name: overriddenName,
connections: [['mac', deviceId]],
manufacturer: undefined,
viaDevice: 'room-assistant-distributed',
},
},
},
]
);
});

it('should trigger regular sensor state updates if the inquiries switch is on', () => {
jest.spyOn(service, 'shouldInquire').mockReturnValue(true);
config.preserveState = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,17 +333,19 @@ export class BluetoothClassicService
sensorId: string,
device: Device
): Promise<RoomPresenceDistanceSensor> {
const baseName =
this.config.entityOverrides[device.address]?.name || device.name;
const deviceInfo: DeviceInfo = {
identifiers: device.address,
name: device.name,
name: baseName,
manufacturer: device.manufacturer,
connections: [['mac', device.address]],
viaDevice: DISTRIBUTED_DEVICE_ID,
};

const deviceTracker = this.createDeviceTracker(
makeId(`${sensorId}-tracker`),
`${device.name} Tracker`,
`${baseName} Tracker`,
deviceInfo
);

Expand All @@ -358,7 +360,7 @@ export class BluetoothClassicService
];
const rawSensor = new RoomPresenceDistanceSensor(
sensorId,
`${device.name} Room Presence`,
`${baseName} Room Presence`,
0
);
const sensorProxy = new Proxy<RoomPresenceDistanceSensor>(
Expand Down

0 comments on commit d0c5c52

Please sign in to comment.