using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Haoliang.Models.System; using Haoliang.Models.Device; using Haoliang.Models.DataCollection; using Haoliang.Data.Repositories; using Haoliang.Core.Services; namespace Haoliang.Core.Services { public interface IAlarmService { Task CreateAlarmAsync(Alarm alarm); Task UpdateAlarmAsync(int alarmId, Alarm alarm); Task DeleteAlarmAsync(int alarmId); Task GetAlarmByIdAsync(int alarmId); Task> GetAllAlarmsAsync(); Task> GetAlarmsByDeviceAsync(int deviceId); Task> GetAlarmsByTypeAsync(AlarmType type); Task> GetActiveAlarmsAsync(); Task> GetAlarmsByDateRangeAsync(DateTime startDate, DateTime endDate); Task ResolveAlarmAsync(int alarmId, string resolutionNote); Task AcknowledgeAlarmAsync(int alarmId, string acknowledgeNote); Task GetAlarmStatisticsAsync(DateTime date); Task> GetCriticalAlarmsAsync(); Task> GetDeviceAlarmsAsync(int deviceId, int days = 7); } public interface IAlarmRuleService { Task CreateAlarmRuleAsync(AlarmRule rule); Task UpdateAlarmRuleAsync(int ruleId, AlarmRule rule); Task DeleteAlarmRuleAsync(int ruleId); Task GetAlarmRuleByIdAsync(int ruleId); Task> GetAllAlarmRulesAsync(); Task> GetActiveAlarmRulesAsync(); Task> GetRulesByDeviceAsync(int deviceId); Task EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status); Task GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status); Task TestAlarmRuleAsync(int ruleId); } public interface IAlarmNotificationService { Task SendAlarmNotificationAsync(Alarm alarm); Task SendBulkAlarmNotificationsAsync(IEnumerable alarms); Task SendSmsNotificationAsync(string phoneNumber, string message); Task SendEmailNotificationAsync(string email, string subject, string message); Task SendWechatNotificationAsync(string openId, string message); Task> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate); Task ConfigureNotificationChannelAsync(NotificationChannel channel); Task> GetAvailableChannelsAsync(); } public class AlarmManager : IAlarmService { private readonly IAlarmRepository _alarmRepository; private readonly IAlarmRuleService _alarmRuleService; private readonly IAlarmNotificationService _notificationService; public AlarmManager( IAlarmRepository alarmRepository, IAlarmRuleService alarmRuleService, IAlarmNotificationService notificationService) { _alarmRepository = alarmRepository; _alarmRuleService = alarmRuleService; _notificationService = notificationService; } public async Task CreateAlarmAsync(Alarm alarm) { // 设置初始状态 alarm.AlarmStatus = AlarmStatus.Active; alarm.CreateTime = DateTime.Now; alarm.UpdateTime = DateTime.Now; var createdAlarm = await _alarmRepository.AddAsync(alarm); // 发送告警通知 await _notificationService.SendAlarmNotificationAsync(createdAlarm); return createdAlarm; } public async Task UpdateAlarmAsync(int alarmId, Alarm alarm) { var existingAlarm = await _alarmRepository.GetByIdAsync(alarmId); if (existingAlarm == null) { throw new KeyNotFoundException($"Alarm with ID {alarmId} not found"); } // 更新字段 alarm.AlarmId = alarmId; alarm.UpdateTime = DateTime.Now; var updatedAlarm = await _alarmRepository.UpdateAsync(alarm); return updatedAlarm; } public async Task DeleteAlarmAsync(int alarmId) { return await _alarmRepository.DeleteAsync(alarmId); } public async Task GetAlarmByIdAsync(int alarmId) { return await _alarmRepository.GetByIdAsync(alarmId); } public async Task> GetAllAlarmsAsync() { return await _alarmRepository.GetAllAsync(); } public async Task> GetAlarmsByDeviceAsync(int deviceId) { return await _alarmRepository.GetByDeviceIdAsync(deviceId); } public async Task> GetAlarmsByTypeAsync(AlarmType type) { return await _alarmRepository.GetByAlarmTypeAsync(type); } public async Task> GetActiveAlarmsAsync() { return await _alarmRepository.GetByStatusAsync(AlarmStatus.Active); } public async Task> GetAlarmsByDateRangeAsync(DateTime startDate, DateTime endDate) { return await _alarmRepository.GetByDateRangeAsync(startDate, endDate); } public async Task ResolveAlarmAsync(int alarmId, string resolutionNote) { var alarm = await _alarmRepository.GetByIdAsync(alarmId); if (alarm == null) { return false; } alarm.AlarmStatus = AlarmStatus.Resolved; alarm.ResolutionNote = resolutionNote; alarm.ResolvedTime = DateTime.Now; alarm.UpdateTime = DateTime.Now; return await _alarmRepository.UpdateAsync(alarm) != null; } public async Task AcknowledgeAlarmAsync(int alarmId, string acknowledgeNote) { var alarm = await _alarmRepository.GetByIdAsync(alarmId); if (alarm == null) { return false; } alarm.AlarmStatus = AlarmStatus.Acknowledged; alarm.AcknowledgeNote = acknowledgeNote; alarm.AcknowledgedTime = DateTime.Now; alarm.UpdateTime = DateTime.Now; return await _alarmRepository.UpdateAsync(alarm) != null; } public async Task GetAlarmStatisticsAsync(DateTime date) { return await _alarmRepository.GetAlarmStatisticsAsync(date); } public async Task> GetCriticalAlarmsAsync() { return await _alarmRepository.GetBySeverityAsync(AlarmSeverity.Critical); } public async Task> GetDeviceAlarmsAsync(int deviceId, int days = 7) { var startDate = DateTime.Now.AddDays(-days); var endDate = DateTime.Now; return await _alarmRepository.GetByDeviceAndDateRangeAsync(deviceId, startDate, endDate); } } public class AlarmRuleService : IAlarmRuleService { private readonly IAlarmRuleRepository _ruleRepository; private readonly IAlarmRepository _alarmRepository; private readonly IDeviceRepository _deviceRepository; private readonly ILoggerService _logger; public AlarmRuleService( IAlarmRuleRepository ruleRepository, IAlarmRepository alarmRepository, IDeviceRepository deviceRepository, ILoggerService logger) { _ruleRepository = ruleRepository; _alarmRepository = alarmRepository; _deviceRepository = deviceRepository; _logger = logger; } public async Task CreateAlarmRuleAsync(AlarmRule rule) { rule.IsActive = true; rule.CreateTime = DateTime.Now; rule.UpdateTime = DateTime.Now; return await _ruleRepository.AddAsync(rule); } public async Task UpdateAlarmRuleAsync(int ruleId, AlarmRule rule) { var existingRule = await _ruleRepository.GetByIdAsync(ruleId); if (existingRule == null) { throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found"); } rule.RuleId = ruleId; rule.UpdateTime = DateTime.Now; return await _ruleRepository.UpdateAsync(rule); } public async Task DeleteAlarmRuleAsync(int ruleId) { return await _ruleRepository.DeleteAsync(ruleId); } public async Task GetAlarmRuleByIdAsync(int ruleId) { return await _ruleRepository.GetByIdAsync(ruleId); } public async Task> GetAllAlarmRulesAsync() { return await _ruleRepository.GetAllAsync(); } public async Task> GetActiveAlarmRulesAsync() { return await _ruleRepository.GetByStatusAsync(true); } public async Task> GetRulesByDeviceAsync(int deviceId) { return await _ruleRepository.GetByDeviceIdAsync(deviceId); } public async Task EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status) { if (!rule.IsActive || status == null) return false; try { switch (rule.RuleType) { case AlarmRuleType.DeviceOffline: return EvaluateDeviceOfflineRule(rule, status); case AlarmRuleType.TemperatureHigh: return EvaluateTemperatureRule(rule, status); case AlarmRuleType.PressureHigh: return EvaluatePressureRule(rule, status); case AlarmRuleType.ProductionStop: return EvaluateProductionStopRule(rule, status); case AlarmRuleType.NetworkError: return EvaluateNetworkErrorRule(rule, status); default: return false; } } catch (Exception ex) { await _logger.LogErrorAsync($"Failed to evaluate alarm rule {rule.RuleId}: {ex.Message}"); return false; } } public async Task GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status) { var alarm = new Alarm { DeviceId = status.DeviceId, DeviceCode = "", // Will be populated from device AlarmType = rule.AlarmType, Severity = rule.Severity, Title = rule.AlarmTitle, Description = rule.AlarmDescription, AlarmStatus = AlarmStatus.Active, RuleId = rule.RuleId, CreateTime = DateTime.Now, UpdateTime = DateTime.Now }; // Get device code var device = await _deviceRepository.GetByIdAsync(status.DeviceId); if (device != null) { alarm.DeviceCode = device.DeviceCode; } return alarm; } public async Task TestAlarmRuleAsync(int ruleId) { var rule = await _ruleRepository.GetByIdAsync(ruleId); if (rule == null) throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found"); // Get a sample device status for testing var devices = await _deviceRepository.GetAllAsync(); if (!devices.Any()) throw new Exception("No devices available for testing"); var sampleDevice = devices.First(); var deviceStatus = new DeviceCurrentStatus { DeviceId = sampleDevice.Id, Status = "Running", IsRunning = true, NCProgram = "O1234", CumulativeCount = 1000, RecordTime = DateTime.Now }; // Evaluate the rule var shouldTrigger = await EvaluateAlarmRuleAsync(rule, deviceStatus); if (shouldTrigger) { var alarm = await GenerateAlarmFromRuleAsync(rule, deviceStatus); alarm.Title = $"Test Alarm: {rule.AlarmTitle}"; alarm.Description = $"This is a test alarm for rule '{rule.RuleName}'."; await _alarmRepository.AddAsync(alarm); await _alarmRepository.SaveAsync(); await _logger.LogInformationAsync($"Test alarm created for rule {rule.RuleId}"); } else { await _logger.LogInformationAsync($"Rule {rule.RuleId} did not trigger alarm during test"); } } private bool EvaluateDeviceOfflineRule(AlarmRule rule, DeviceCurrentStatus status) { // Check if device status indicates offline return status.Status?.ToLower() == "offline" || !status.IsRunning || string.IsNullOrEmpty(status.NCProgram); } private bool EvaluateTemperatureRule(AlarmRule rule, DeviceCurrentStatus status) { // Find temperature tag var temperatureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("temp") == true || t.Id?.Contains("温度") == true); if (temperatureTag == null || temperatureTag.Value == null) return false; if (decimal.TryParse(temperatureTag.Value.ToString(), out decimal temperature)) { return temperature > rule.ThresholdValue; } return false; } private bool EvaluatePressureRule(AlarmRule rule, DeviceCurrentStatus status) { // Find pressure tag var pressureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("pressure") == true || t.Id?.Contains("压力") == true); if (pressureTag == null || pressureTag.Value == null) return false; if (decimal.TryParse(pressureTag.Value.ToString(), out decimal pressure)) { return pressure > rule.ThresholdValue; } return false; } private bool EvaluateProductionStopRule(AlarmRule rule, DeviceCurrentStatus status) { // Check if device has been stopped for specified duration var stopDuration = TimeSpan.FromMinutes(rule.ThresholdValue); return !status.IsRunning && status.RecordTime < DateTime.Now.Subtract(stopDuration); } private bool EvaluateNetworkErrorRule(AlarmRule rule, DeviceCurrentStatus status) { // Check for network-related errors in status return status.Tags?.Any(t => t.Id?.Contains("error") == true && t.Value?.ToString() == "1") == true; } } public class AlarmNotificationService : IAlarmNotificationService { private readonly IAlarmNotificationRepository _notificationRepository; private readonly IEmailService _emailService; private readonly ISmsService _smsService; private readonly IWechatService _wechatService; private readonly ILoggerService _logger; private readonly IDeviceRepository _deviceRepository; public AlarmNotificationService( IAlarmNotificationRepository notificationRepository, IEmailService emailService, ISmsService smsService, IWechatService wechatService, ILoggerService logger, IDeviceRepository deviceRepository) { _notificationRepository = notificationRepository; _emailService = emailService; _smsService = smsService; _wechatService = wechatService; _logger = logger; _deviceRepository = deviceRepository; } public async Task SendAlarmNotificationAsync(Alarm alarm) { try { var device = await _deviceRepository.GetByIdAsync(alarm.DeviceId); var notificationChannels = await GetNotificationChannelsForDevice(alarm.DeviceId); foreach (var channel in notificationChannels) { if (channel.IsEnabled) { await SendNotificationViaChannel(alarm, channel, device); } } // Log the notification await LogNotificationSent(alarm, notificationChannels.Count()); } catch (Exception ex) { await _logger.LogErrorAsync($"Failed to send alarm notification for alarm {alarm.AlarmId}: {ex.Message}"); } } public async Task SendBulkAlarmNotificationsAsync(IEnumerable alarms) { foreach (var alarm in alarms) { await SendAlarmNotificationAsync(alarm); } } public async Task SendSmsNotificationAsync(string phoneNumber, string message) { try { return await _smsService.SendSmsAsync(phoneNumber, message); } catch (Exception ex) { await _logger.LogErrorAsync($"Failed to send SMS to {phoneNumber}: {ex.Message}"); return false; } } public async Task SendEmailNotificationAsync(string email, string subject, string message) { try { return await _emailService.SendEmailAsync(email, subject, message); } catch (Exception ex) { await _logger.LogErrorAsync($"Failed to send email to {email}: {ex.Message}"); return false; } } public async Task SendWechatNotificationAsync(string openId, string message) { try { return await _wechatService.SendMessageAsync(openId, message); } catch (Exception ex) { await _logger.LogErrorAsync($"Failed to send WeChat message to {openId}: {ex.Message}"); return false; } } public async Task> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate) { return await _notificationRepository.GetByDateRangeAsync(startDate, endDate); } public async Task ConfigureNotificationChannelAsync(NotificationChannel channel) { // Validate channel configuration if (!ValidateChannelConfiguration(channel)) return false; // Save channel configuration return await _notificationRepository.SaveChannelAsync(channel); } public async Task> GetAvailableChannelsAsync() { return await _notificationRepository.GetAllChannelsAsync(); } private async Task> GetNotificationChannelsForDevice(int deviceId) { // This would typically query the database for device-specific notification settings // For now, return a default set of channels return new List { new NotificationChannel { ChannelType = NotificationChannelType.Email, IsEnabled = true }, new NotificationChannel { ChannelType = NotificationChannelType.Sms, IsEnabled = false }, new NotificationChannel { ChannelType = NotificationChannelType.WeChat, IsEnabled = false } }; } private async Task SendNotificationViaChannel(Alarm alarm, NotificationChannel channel, Device device) { var message = FormatAlarmMessage(alarm, device); var subject = $"Alarm: {alarm.AlarmType} - {device?.DeviceCode}"; switch (channel.ChannelType) { case NotificationChannelType.Email: if (!string.IsNullOrEmpty(channel.Recipient)) { await SendEmailNotificationAsync(channel.Recipient, subject, message); } break; case NotificationChannelType.Sms: if (!string.IsNullOrEmpty(channel.Recipient)) { await SendSmsNotificationAsync(channel.Recipient, message); } break; case NotificationChannelType.WeChat: if (!string.IsNullOrEmpty(channel.Recipient)) { await SendWechatNotificationAsync(channel.Recipient, message); } break; } } private string FormatAlarmMessage(Alarm alarm, Device device) { return $"🚨 Alarm Alert\n\n" + $"Device: {device?.DeviceCode} ({device?.DeviceName})\n" + $"Type: {alarm.AlarmType}\n" + $"Severity: {alarm.Severity}\n" + $"Title: {alarm.Title}\n" + $"Description: {alarm.Description}\n" + $"Time: {alarm.CreateTime:yyyy-MM-dd HH:mm:ss}\n" + $"Device ID: {alarm.DeviceId}"; } private bool ValidateChannelConfiguration(NotificationChannel channel) { switch (channel.ChannelType) { case NotificationChannelType.Email: return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.Contains("@"); case NotificationChannelType.Sms: return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.All(char.IsDigit); case NotificationChannelType.WeChat: return !string.IsNullOrEmpty(channel.Recipient); default: return false; } } private async Task LogNotificationSent(Alarm alarm, int channelCount) { var notification = new AlarmNotification { AlarmId = alarm.AlarmId, NotificationTime = DateTime.Now, ChannelsUsed = channelCount, Success = true }; await _notificationRepository.AddNotificationAsync(notification); } } // Additional supporting classes and interfaces public interface IEmailService { Task SendEmailAsync(string email, string subject, string message); } public interface ISmsService { Task SendSmsAsync(string phoneNumber, string message); } public interface IWechatService { Task SendMessageAsync(string openId, string message); } public interface IAlarmRuleRepository { Task AddAsync(AlarmRule rule); Task UpdateAsync(AlarmRule rule); Task DeleteAsync(int ruleId); Task GetByIdAsync(int ruleId); Task> GetAllAsync(); Task> GetByStatusAsync(bool isActive); Task> GetByDeviceIdAsync(int deviceId); } public interface IAlarmNotificationRepository { Task AddNotificationAsync(AlarmNotification notification); Task> GetByDateRangeAsync(DateTime startDate, DateTime endDate); Task SaveChannelAsync(NotificationChannel channel); Task> GetAllChannelsAsync(); } }