Skip to content

Commit

Permalink
fix(home-assistant): correctly format array in entity configs
Browse files Browse the repository at this point in the history
The recent change to allow for objects within array to be formatted
overlooked arrays like the one used for device connections, which ended
up being formatted as an object instead. This should e.g. fix BT Classic
entities not being available in HA anymore.

Closes #728
  • Loading branch information
mKeRix committed May 27, 2021
1 parent f948141 commit 0f0dc24
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 28 deletions.
76 changes: 50 additions & 26 deletions src/integrations/home-assistant/home-assistant.service.spec.ts
Expand Up @@ -311,9 +311,7 @@ describe('HomeAssistantService', () => {
await service.onModuleInit();
service.handleNewEntity(new Switch('test-switch', 'Test Switch'));

expect(
mockMqttClient.subscribe
).toHaveBeenCalledWith(
expect(mockMqttClient.subscribe).toHaveBeenCalledWith(
'room-assistant/switch/test-instance-test-switch/command',
{ qos: 0 }
);
Expand Down Expand Up @@ -439,6 +437,26 @@ describe('HomeAssistantService', () => {
);
});

it('should format device connections correctly', async () => {
await service.onModuleInit();
service.handleNewEntity(new Sensor('test', 'Test'), [
{
for: SensorConfig,
overrides: {
device: {
connections: [['mac', '12:34']],
},
},
},
]);

expect(
JSON.parse(mockMqttClient.publish.mock.calls[1][1]).device
).toEqual({
connections: [['mac', '12:34']],
});
});

it('should apply sensor customizations to the discovery message', async () => {
await service.onModuleInit();
service.handleNewEntity(new Sensor('custom-sensor', 'Custom'), [
Expand Down Expand Up @@ -492,11 +510,13 @@ describe('HomeAssistantService', () => {
it('should send an instance online status on startup', async () => {
await service.onModuleInit();

expect(
mockMqttClient.publish
).toHaveBeenCalledWith('room-assistant/status/test-instance', 'online', {
qos: 1,
});
expect(mockMqttClient.publish).toHaveBeenCalledWith(
'room-assistant/status/test-instance',
'online',
{
qos: 1,
}
);
});

it('should configure a last will message', async () => {
Expand Down Expand Up @@ -544,11 +564,13 @@ describe('HomeAssistantService', () => {

service.sendHeartbeats();

expect(
mockMqttClient.publish
).toHaveBeenCalledWith('room-assistant/status/test-instance', 'online', {
qos: 1,
});
expect(mockMqttClient.publish).toHaveBeenCalledWith(
'room-assistant/status/test-instance',
'online',
{
qos: 1,
}
);
});

it('should send entity status messages as heartbeat', async () => {
Expand Down Expand Up @@ -589,11 +611,13 @@ describe('HomeAssistantService', () => {

mqttEmitter.emit('connect');

expect(
mockMqttClient.publish
).toHaveBeenCalledWith('room-assistant/status/test-instance', 'online', {
qos: 1,
});
expect(mockMqttClient.publish).toHaveBeenCalledWith(
'room-assistant/status/test-instance',
'online',
{
qos: 1,
}
);
});

it('should update availability topics of distributed entities if instance is elected as new leader', async () => {
Expand All @@ -608,9 +632,7 @@ describe('HomeAssistantService', () => {

clusterService.emit('elected', { id: 'new-leader' });

expect(
mockMqttClient.publish
).toHaveBeenCalledWith(
expect(mockMqttClient.publish).toHaveBeenCalledWith(
'homeassistant/sensor/room-assistant/test/config',
expect.any(String),
{ qos: 0, retain: true }
Expand Down Expand Up @@ -665,11 +687,13 @@ describe('HomeAssistantService', () => {

await service.onApplicationShutdown();

expect(
mockMqttClient.publish
).toHaveBeenCalledWith('room-assistant/status/test-instance', 'offline', {
qos: 1,
});
expect(mockMqttClient.publish).toHaveBeenCalledWith(
'room-assistant/status/test-instance',
'offline',
{
qos: 1,
}
);
});

it('should send offline messages for local entities on shutdown', async () => {
Expand Down
14 changes: 12 additions & 2 deletions src/integrations/home-assistant/home-assistant.service.ts
Expand Up @@ -44,7 +44,8 @@ const INSTANCE_STATUS_BASE_TOPIC = 'room-assistant/status';

@Injectable()
export class HomeAssistantService
implements OnModuleInit, OnApplicationShutdown {
implements OnModuleInit, OnApplicationShutdown
{
private config: HomeAssistantConfig;
private device: Device;
private entityConfigs: Map<string, EntityConfig> = new Map<
Expand Down Expand Up @@ -423,6 +424,10 @@ export class HomeAssistantService
protected formatMessage(message: object): object {
const filteredMessage = _.omit(message, PROPERTY_DENYLIST);
return this.deepMap(filteredMessage, (obj) => {
if (!_.isObject(obj) || _.isArray(obj)) {
return obj;
}

return _.mapKeys(obj, (v, k) => {
return _.snakeCase(k);
});
Expand Down Expand Up @@ -579,8 +584,13 @@ export class HomeAssistantService
* @param mapper - Function to apply to all items
*/
private deepMap(obj: object, mapper: (v: object) => object): object {
const mappingMethod: (
obj: object,
callback: (v: object) => object
) => object = _.isArray(obj) ? _.map : _.mapValues;

return mapper(
_.mapValues(obj, (v) => {
mappingMethod(obj, (v) => {
if (_.isArray(v)) {
return [...v].map((e) => this.deepMap(e, mapper));
} else if (_.isObject(v)) {
Expand Down

0 comments on commit 0f0dc24

Please sign in to comment.