Complete IoT monitoring platform for Acuvim II power meters via ESP32. Firmware (Phases 1-7): - ESP32-WROVER-B (TTGO T-Call v1.4) with RS485 Modbus RTU - WiFi STA+AP concurrent mode with GSM/GPRS failover - Transport abstraction layer with 4 priority modes - MQTT protocol with 20 commands, LWT, QoS, exponential backoff - SD card offline buffering with JSONL rotation and non-blocking drain - OTA firmware updates with dual partition rollback protection - Watchdog timer, crash loop detection, Acuvim health monitoring - Captive portal provisioning with AP mode Console backend (Phase 8): - .NET 10 minimal API with PostgreSQL + EF Core - JWT authentication, SignalR real-time updates - MQTTnet 5.x bridge service with health monitoring - Device, telemetry, firmware, alert, group management - Rate limiting, security headers, Swagger/OpenAPI Frontend (Phase 9): - React 18 + TypeScript + Vite with Ant Design 5 - ECharts telemetry visualization, TanStack Query - SignalR live updates, device management UI - Dashboard, fleet management, firmware deployment Testing & Production (Phase 10): - 28 firmware unit tests (Modbus, JSON, config, version) - 23 xUnit backend tests (device, telemetry, command, alert) - Docker Compose with nginx, TLS MQTT, PostgreSQL - Production deployment, commissioning, and troubleshooting docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
54 lines
1.8 KiB
C#
54 lines
1.8 KiB
C#
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Tau.Acuvim.Console.Data;
|
|
|
|
namespace Tau.Acuvim.Console.Tests;
|
|
|
|
/// <summary>
|
|
/// A subclass of AppDbContext that adds a ValueConverter for JsonDocument properties,
|
|
/// which the InMemory provider does not natively support.
|
|
/// </summary>
|
|
public class TestAppDbContext : AppDbContext
|
|
{
|
|
public TestAppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
base.OnModelCreating(modelBuilder);
|
|
|
|
// The InMemory provider cannot handle JsonDocument types.
|
|
// Add a value converter that serialises JsonDocument to/from string.
|
|
var jsonDocConverter = new ValueConverter<JsonDocument?, string?>(
|
|
v => v == null ? null : v.RootElement.GetRawText(),
|
|
v => v == null ? null : JsonDocument.Parse(v, new JsonDocumentOptions()));
|
|
|
|
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
|
{
|
|
foreach (var property in entityType.GetProperties())
|
|
{
|
|
if (property.ClrType == typeof(JsonDocument))
|
|
{
|
|
property.SetValueConverter(jsonDocConverter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class TestHelpers
|
|
{
|
|
public static AppDbContext CreateDbContext([System.Runtime.CompilerServices.CallerMemberName] string? name = null)
|
|
{
|
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
|
.UseInMemoryDatabase(databaseName: $"{name}_{Guid.NewGuid():N}")
|
|
.Options;
|
|
|
|
return new TestAppDbContext(options);
|
|
}
|
|
|
|
public static ILogger<T> CreateLogger<T>() => NullLogger<T>.Instance;
|
|
}
|