116 lines
4.8 KiB
C#
116 lines
4.8 KiB
C#
using Model.Dto.Inspection;
|
|
using Model.Entity.Inspection;
|
|
using ORM;
|
|
using Service.Interface;
|
|
|
|
namespace WebAPI.Services
|
|
{
|
|
/// <summary>
|
|
/// 温度箱数据模拟器(临时用)
|
|
/// 每秒为 100 台环境箱生成一条模拟温湿度数据并批量写入数据库,
|
|
/// 真实设备接入后删除此类及 Program.cs 中的注册即可
|
|
/// </summary>
|
|
public class TemperatureBoxSimulator : BackgroundService
|
|
{
|
|
private const int DeviceCount = 100;
|
|
private const double AlarmTemp = 80.0; // 高温报警阈值
|
|
private static readonly Random Rnd = new();
|
|
|
|
// 每台设备维护一份模拟状态(随机游走需要基于上一次的值)
|
|
private class BoxState
|
|
{
|
|
public double Temperature = Rnd.Next(20, 60);
|
|
public double Humidity = Rnd.Next(30, 70);
|
|
}
|
|
|
|
private readonly Dictionary<string, BoxState> _states = new();
|
|
private readonly IServiceScopeFactory _scopeFactory;
|
|
|
|
public TemperatureBoxSimulator(IServiceScopeFactory scopeFactory)
|
|
{
|
|
_scopeFactory = scopeFactory;
|
|
for (int i = 1; i <= DeviceCount; i++)
|
|
{
|
|
_states[$"BOX-{i:D3}"] = new BoxState();
|
|
}
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
var now = DateTime.Now;
|
|
var batch = new List<TemperatureBoxDataEntity>(DeviceCount);
|
|
var alarmDevices = new List<(string Code, double Temp)>();
|
|
|
|
foreach (var kv in _states)
|
|
{
|
|
var s = kv.Value;
|
|
// 随机游走,让曲线平滑连续
|
|
s.Temperature = Math.Clamp(s.Temperature + (Rnd.NextDouble() - 0.48) * 2, 15, 95);
|
|
s.Humidity = Math.Clamp(s.Humidity + (Rnd.NextDouble() - 0.5) * 3, 20, 90);
|
|
|
|
bool alarm = s.Temperature >= AlarmTemp;
|
|
if (alarm)
|
|
{
|
|
alarmDevices.Add((kv.Key, Math.Round(s.Temperature, 1)));
|
|
}
|
|
batch.Add(new TemperatureBoxDataEntity
|
|
{
|
|
DeviceCode = kv.Key,
|
|
DeviceType = "TemperatureBox",
|
|
DeviceTemperature = Math.Round(s.Temperature, 1),
|
|
DeviceHumidity = Math.Round(s.Humidity, 1),
|
|
Status = alarm ? "报警" : "运行",
|
|
AlarmInfo = alarm ? "温度超限报警" : "",
|
|
CreateTime = now
|
|
});
|
|
}
|
|
|
|
// 批量插入
|
|
await SqlSugarContext.DbContext.Insertable(batch).ExecuteCommandAsync();
|
|
|
|
// 报警设备上报告警中心(告警中心内部有 5 分钟合并窗口,不会每秒重复建告警)
|
|
if (alarmDevices.Count > 0)
|
|
{
|
|
// 单例 HostedService 不能直接注入 Scoped 服务,按批次创建作用域解析
|
|
using var scope = _scopeFactory.CreateScope();
|
|
var alertCenter = scope.ServiceProvider.GetRequiredService<IAlertCenterService>();
|
|
foreach (var (code, temp) in alarmDevices)
|
|
{
|
|
await alertCenter.RaiseAsync(new AlertRaiseDto
|
|
{
|
|
Source = AlertSourceEnum.Collection,
|
|
DeviceCode = code,
|
|
DeviceName = $"温度箱 {code}",
|
|
DeviceType = "TemperatureBox",
|
|
Metric = "Temperature",
|
|
AlertType = AlertTypeEnum.ThresholdExceed,
|
|
AlertLevel = AlertLevelEnum.Urgent,
|
|
CurrentValue = temp,
|
|
ThresholdValue = AlarmTemp,
|
|
Content = $"温度箱 {code} 温度超限:当前 {temp}℃ ≥ 报警阈值 {AlarmTemp}℃"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[温度箱模拟器] 写入失败: {ex.Message}");
|
|
}
|
|
|
|
try
|
|
{
|
|
await Task.Delay(1000, stoppingToken);
|
|
}
|
|
catch (TaskCanceledException)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|