namespace Evergreen.Health.Application.Health.Integrations.Ib43; public sealed class Ib43Options { public bool Enabled { get; set; } public string Host { get; set; } = "192.168.2.2"; public int Port { get; set; } = 1883; public bool UseTls { get; set; } public string Username { get; set; } = "evergreen-backend"; public string Password { get; set; } = ""; public string ClientId { get; set; } = "evergreen-health-backend"; public int StaleAfterSeconds { get; set; } = 150; public List Devices { get; set; } = []; public bool IsValid() => !Enabled || (!string.IsNullOrWhiteSpace(Host) && Port is > 0 and <= 65535 && !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password) && !string.IsNullOrWhiteSpace(ClientId) && StaleAfterSeconds > 0 && Devices is { Count: > 0 } && Devices.All(d => d != null && ValidSegment(d.ProductKey) && ValidSegment(d.SerialNumber) && d.PersonLeftIndex is null or 0 or 1) && Devices.Select(d => d.PostTopic).Distinct(StringComparer.Ordinal).Count() == Devices.Count); private static bool ValidSegment(string value) => !string.IsNullOrWhiteSpace(value) && !value.Any(c => c is '/' or '+' or '#' || char.IsControl(c)); } public sealed class Ib43Binding { public string ProductKey { get; set; } = ""; public string SerialNumber { get; set; } = ""; public bool Simulation { get; set; } = true; // 实机验证前保持 null;不可从数组顺序猜左右。 public int? PersonLeftIndex { get; set; } public string PostTopic => $"/sys/{ProductKey}/{SerialNumber}/thing/property/post"; }