8550ed8d9e
ci / build-test (push) Successful in 1m16s
HomeAssistantWebSocketWorker holds a persistent state_changed subscription per HA endpoint that opts in via the connector's WebSocket toggle (HaEndpointConfig.UseWebSocket): auth handshake, subscribe, ingest in real time, capped-backoff reconnect. The REST poll worker skips WS endpoints so each is served once. HaWebSocketProtocol holds the pure handshake/parse logic. Verified by 11 protocol unit tests + a live integration test against an in-process fake HA server. CLAUDE.md updated. Claude-Session: https://claude.ai/code/session_01Kib2MniVFbD95fkgLgBBnB
64 lines
2.9 KiB
C#
64 lines
2.9 KiB
C#
using MeterVault.Core.Normalization;
|
|
using MeterVault.Infrastructure.Import;
|
|
using MeterVault.Infrastructure.Ingestion;
|
|
using MeterVault.Infrastructure.Normalization;
|
|
using MeterVault.Infrastructure.Persistence;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace MeterVault.Infrastructure;
|
|
|
|
/// <summary>Composition root for the infrastructure layer (persistence, ingestion, import).</summary>
|
|
public static class DependencyInjection
|
|
{
|
|
public static IServiceCollection AddMeterVaultInfrastructure(
|
|
this IServiceCollection services,
|
|
string connectionString)
|
|
{
|
|
// A factory (for per-operation contexts in Blazor components/read services — a shared
|
|
// circuit-scoped DbContext is not thread-safe) plus a scoped context (from the factory)
|
|
// for request/tick-scoped services (API, workers, importers) that inject it directly.
|
|
services.AddDbContextFactory<MeterVaultDbContext>(options =>
|
|
options
|
|
.UseNpgsql(connectionString, npgsql =>
|
|
npgsql.MigrationsAssembly(typeof(MeterVaultDbContext).Assembly.FullName))
|
|
.UseSnakeCaseNamingConvention());
|
|
services.AddScoped<MeterVaultDbContext>(sp =>
|
|
sp.GetRequiredService<IDbContextFactory<MeterVaultDbContext>>().CreateDbContext());
|
|
|
|
services.AddSingleton<INormalizationEngine>(_ => NormalizationEngine.CreateDefault());
|
|
services.AddScoped<NormalizationService>();
|
|
services.AddScoped<CsvImporter>();
|
|
services.AddScoped<ImportService>();
|
|
services.AddScoped<ReferenceDataImporter>();
|
|
services.AddScoped<IngestionService>();
|
|
services.AddScoped<MqttMessageRouter>();
|
|
// HttpClient + HA tester are available even with live ingestion off, so the admin
|
|
// "Test connection" works without the background workers running.
|
|
services.AddHttpClient();
|
|
services.AddScoped<HaConnectionTester>();
|
|
services.AddScoped<Costing.CostService>();
|
|
services.AddScoped<Dashboard.DashboardService>();
|
|
services.AddScoped<Dashboard.SolarService>();
|
|
services.AddScoped<Dashboard.ConsumableService>();
|
|
services.AddScoped<Dashboard.MeterDetailService>();
|
|
services.AddScoped<Dashboard.FlowService>();
|
|
services.AddScoped<Backup.ExportService>();
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers the live-ingestion background workers (MQTT/Tasmota + Home Assistant). Kept
|
|
/// separate from <see cref="AddMeterVaultInfrastructure"/> so tests can opt out of brokers.
|
|
/// </summary>
|
|
public static IServiceCollection AddMeterVaultIngestion(this IServiceCollection services)
|
|
{
|
|
services.AddHttpClient();
|
|
services.AddHostedService<MqttIngestionWorker>();
|
|
services.AddHostedService<HomeAssistantWorker>();
|
|
services.AddHostedService<HomeAssistantWebSocketWorker>();
|
|
return services;
|
|
}
|
|
}
|