diff --git a/src/integrations/home-assistant/home-assistant.health.spec.ts b/src/integrations/home-assistant/home-assistant.health.spec.ts new file mode 100644 index 0000000..a4db616 --- /dev/null +++ b/src/integrations/home-assistant/home-assistant.health.spec.ts @@ -0,0 +1,31 @@ +import { HomeAssistantHealthIndicator } from './home-assistant.health'; +import { HomeAssistantService } from './home-assistant.service'; +import { HealthCheckError } from '@nestjs/terminus'; + +describe('HomeAssistantHealthIndicator', () => { + const serviceMock = { + isConnected: jest.fn(), + }; + const healthIndicator = new HomeAssistantHealthIndicator( + (serviceMock as unknown) as HomeAssistantService + ); + + it('should report healthy if connection is established', () => { + serviceMock.isConnected.mockReturnValue(true); + + const result = healthIndicator.connectionCheck(); + expect(result['ha_mqtt_connected'].status).toEqual('up'); + }); + + it('should report unhealthy if connection not established yet', () => { + serviceMock.isConnected.mockReturnValue(undefined); + + expect(() => healthIndicator.connectionCheck()).toThrow(HealthCheckError); + }); + + it('should report unhealthy if connection lost', () => { + serviceMock.isConnected.mockReturnValue(false); + + expect(() => healthIndicator.connectionCheck()).toThrow(HealthCheckError); + }); +}); diff --git a/src/integrations/home-assistant/home-assistant.health.ts b/src/integrations/home-assistant/home-assistant.health.ts new file mode 100644 index 0000000..c4a0cb6 --- /dev/null +++ b/src/integrations/home-assistant/home-assistant.health.ts @@ -0,0 +1,32 @@ +import { + HealthCheckError, + HealthIndicator, + HealthIndicatorResult, +} from '@nestjs/terminus'; +import { Injectable, Optional } from '@nestjs/common'; +import { HealthIndicatorService } from '../../status/health-indicator.service'; +import { HomeAssistantService } from './home-assistant.service'; + +@Injectable() +export class HomeAssistantHealthIndicator extends HealthIndicator { + constructor( + private readonly homeAssistantService: HomeAssistantService, + @Optional() healthIndicatorService?: HealthIndicatorService + ) { + super(); + healthIndicatorService?.registerHealthIndicator(async () => + this.connectionCheck() + ); + } + + connectionCheck(): HealthIndicatorResult { + const isHealthy = this.homeAssistantService.isConnected(); + const result = this.getStatus('ha_mqtt_connected', isHealthy); + + if (isHealthy) { + return result; + } + + throw new HealthCheckError('No connection to MQTT broker', result); + } +} diff --git a/src/integrations/home-assistant/home-assistant.module.ts b/src/integrations/home-assistant/home-assistant.module.ts index 3724541..2f30217 100644 --- a/src/integrations/home-assistant/home-assistant.module.ts +++ b/src/integrations/home-assistant/home-assistant.module.ts @@ -2,14 +2,16 @@ import { DynamicModule, Module } from '@nestjs/common'; import { HomeAssistantService } from './home-assistant.service'; import { ConfigModule } from '../../config/config.module'; import { EntitiesModule } from '../../entities/entities.module'; +import { StatusModule } from '../../status/status.module'; +import { HomeAssistantHealthIndicator } from './home-assistant.health'; @Module({}) export default class HomeAssistantModule { static forRoot(): DynamicModule { return { module: HomeAssistantModule, - imports: [ConfigModule, EntitiesModule], - providers: [HomeAssistantService], + imports: [ConfigModule, EntitiesModule, StatusModule], + providers: [HomeAssistantService, HomeAssistantHealthIndicator], }; } } diff --git a/src/integrations/home-assistant/home-assistant.service.ts b/src/integrations/home-assistant/home-assistant.service.ts index 755e9da..8bc634a 100644 --- a/src/integrations/home-assistant/home-assistant.service.ts +++ b/src/integrations/home-assistant/home-assistant.service.ts @@ -253,6 +253,13 @@ export class HomeAssistantService } } + /** + * Checks if room-assistant is connected to the MQTT broker. + */ + isConnected(): boolean { + return this.mqttClient?.connected; + } + /** * Handles broker re-connection events. */