diff --git a/src/integrations/bluetooth-classic/bluetooth-classic.service.ts b/src/integrations/bluetooth-classic/bluetooth-classic.service.ts index 88dd527..bc1db79 100644 --- a/src/integrations/bluetooth-classic/bluetooth-classic.service.ts +++ b/src/integrations/bluetooth-classic/bluetooth-classic.service.ts @@ -12,7 +12,6 @@ import * as util from 'util'; import { exec } from 'child_process'; import { Node } from 'democracy'; import { NewRssiEvent } from './new-rssi.event'; -import slugify from 'slugify'; import _ from 'lodash'; import { Interval, SchedulerRegistry } from '@nestjs/schedule'; import { EntityCustomization } from '../../entities/entity-customization.interface'; @@ -23,6 +22,7 @@ import { } from './bluetooth-classic.const'; import { RoomPresenceDistanceSensor } from '../room-presence/room-presence-distance.sensor'; import { KalmanFilterable } from '../../util/filters'; +import { makeId } from '../../util/id'; @Injectable() export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 0.8) @@ -101,9 +101,7 @@ export class BluetoothClassicService extends KalmanFilterable(Object, 1.4, 0.8) `Received RSSI of ${event.rssi} for ${event.address} from ${event.instanceName}` ); - const sensorId = slugify( - _.lowerCase(`bluetooth-classic ${event.address} room presence`) - ); + const sensorId = makeId(`bluetooth-classic ${event.address}`); let sensor: RoomPresenceDistanceSensor; if (this.entitiesService.has(sensorId)) { sensor = this.entitiesService.get(sensorId) as RoomPresenceDistanceSensor; diff --git a/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.spec.ts b/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.spec.ts index 4d83327..f6a2789 100644 --- a/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.spec.ts +++ b/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.spec.ts @@ -410,7 +410,7 @@ describe('BluetoothLowEnergyService', () => { expect(entitiesService.add).toHaveBeenCalledWith( expect.objectContaining({ - id: 'ble-new-room-presence', + id: 'ble-new', name: 'New Tag Room Presence', timeout: 20 }), diff --git a/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.ts b/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.ts index 2771901..1b409d6 100644 --- a/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.ts +++ b/src/integrations/bluetooth-low-energy/bluetooth-low-energy.service.ts @@ -4,8 +4,6 @@ import { OnModuleInit } from '@nestjs/common'; import noble, { Peripheral } from '@abandonware/noble'; -import * as _ from 'lodash'; -import slugify from 'slugify'; import { EntitiesService } from '../../entities/entities.service'; import { IBeacon } from './i-beacon'; import { Tag } from './tag'; @@ -18,6 +16,7 @@ import { SensorConfig } from '../home-assistant/sensor-config'; import { RoomPresenceDistanceSensor } from '../room-presence/room-presence-distance.sensor'; import { SchedulerRegistry } from '@nestjs/schedule'; import { KalmanFilterable } from '../../util/filters'; +import { makeId } from '../../util/id'; export const NEW_DISTANCE_CHANNEL = 'bluetooth-low-energy.new-distance'; @@ -88,7 +87,7 @@ export class BluetoothLowEnergyService extends KalmanFilterable(Object, 0.8, 15) * @param event - Event with new distance data */ handleNewDistance(event: NewDistanceEvent): void { - const sensorId = slugify(_.lowerCase(`ble ${event.tagId} room presence`)); + const sensorId = makeId(`ble ${event.tagId}`); let sensor: RoomPresenceDistanceSensor; if (this.entitiesService.has(sensorId)) { sensor = this.entitiesService.get(sensorId) as RoomPresenceDistanceSensor; diff --git a/src/integrations/home-assistant/entity-config.ts b/src/integrations/home-assistant/entity-config.ts index 7097fbf..6dda50e 100644 --- a/src/integrations/home-assistant/entity-config.ts +++ b/src/integrations/home-assistant/entity-config.ts @@ -1,6 +1,4 @@ import { Device } from './device'; -import slugify from 'slugify'; -import * as _ from 'lodash'; export abstract class EntityConfig { uniqueId: string; @@ -16,15 +14,20 @@ export abstract class EntityConfig { payloadAvailable = 'online'; payloadNotAvailable = 'offline'; - constructor(component: string, id: string, name: string, device?: Device) { + protected constructor( + component: string, + id: string, + name: string, + device?: Device + ) { this.component = component; this.name = name; this.device = device; - this.uniqueId = slugify(_.lowerCase(`room-assistant ${component} ${id}`)); - this.configTopic = `homeassistant/${this.component}/${this.uniqueId}/config`; - this.stateTopic = `roomassistant/${this.component}/${this.uniqueId}/state`; - this.jsonAttributesTopic = `roomassistant/${this.component}/${this.uniqueId}/attributes`; - this.availabilityTopic = `roomassistant/${this.component}/${this.uniqueId}/status`; + this.uniqueId = `room-assistant-${id}`; + this.configTopic = `homeassistant/${this.component}/room-assistant/${id}/config`; + this.stateTopic = `room-assistant/${this.component}/${id}/state`; + this.jsonAttributesTopic = `room-assistant/${this.component}/${id}/attributes`; + this.availabilityTopic = `room-assistant/${this.component}/${id}/status`; } } diff --git a/src/integrations/home-assistant/home-assistant.service.ts b/src/integrations/home-assistant/home-assistant.service.ts index 6cbbe21..0295e44 100644 --- a/src/integrations/home-assistant/home-assistant.service.ts +++ b/src/integrations/home-assistant/home-assistant.service.ts @@ -18,6 +18,7 @@ import { system } from 'systeminformation'; import { InjectEventEmitter } from 'nest-emitter'; import { EntitiesEventEmitter } from '../../entities/entities.events'; import { EntityCustomization } from '../../entities/entity-customization.interface'; +import { makeId } from '../../util/id'; const PROPERTY_BLACKLIST = ['component', 'configTopic']; @@ -161,11 +162,11 @@ export class HomeAssistantService } protected getCombinedId(entityId: string, distributed = false): string { - return `${ + return makeId( distributed - ? 'distributed' - : this.configService.get('global').instanceName - }_${entityId}`; + ? entityId + : [this.configService.get('global').instanceName, entityId].join('-') + ); } protected applyCustomizations( diff --git a/src/util/id.spec.ts b/src/util/id.spec.ts new file mode 100644 index 0000000..fa68e61 --- /dev/null +++ b/src/util/id.spec.ts @@ -0,0 +1,17 @@ +import { makeId } from './id'; + +describe('makeId', () => { + const idRegex = /^[a-z1-9-]+$/; + + it('should convert inputs to lower case', () => { + expect(makeId('ABC-def123')).toMatch(idRegex); + }); + + it('should convert colons to dashes', () => { + expect(makeId('ble-84:87:ad:ef')).toMatch(idRegex); + }); + + it('should convert underscores to dashes', () => { + expect(makeId('bluetooth-classic_129-1-1')).toMatch(idRegex); + }); +}); diff --git a/src/util/id.ts b/src/util/id.ts new file mode 100644 index 0000000..1ebd266 --- /dev/null +++ b/src/util/id.ts @@ -0,0 +1,7 @@ +import slugify from 'slugify'; + +export function makeId(input: string): string { + return slugify(input, { + lower: true + }).replace(/[_:]/g, '-'); +}