AppData.cs 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834
  1. using DBEntity;
  2. using Google.Protobuf;
  3. using ivf_tl_Com;
  4. using ivf_tl_Controller;
  5. using IvfTl.Control.Entity.DBEntitys;
  6. using IvfTl.Control.Entity.DTO;
  7. using IvfTl.Control.Entity.DTO.ApiRequestDTO;
  8. using IvfTl.Control.Entity.DTO.ApiResultDTO;
  9. using IvfTl.Control.Entity.GlobalEntitys;
  10. using IvfTl.Control.Entity.GlobalEnums;
  11. using IvfTl.Control.Entity.InitEntitys;
  12. using IvfTl.Control.Services;
  13. using IvfTl.Control.Services.HttpServices;
  14. using ivf_tl_ServicesImpl.DBServices;
  15. using ivf_tl_ServicesImpl.HttpServices;
  16. using ivf_tl_ServicesImpl.KafkaServices;
  17. using ivf_tl_ServicesImpl.LogServices;
  18. using ivf_tl_ServicesImpl.MqttServices;
  19. using ivf_tl_UtilHelper;
  20. using IvfTl.AutoFocus.Storage;
  21. using NetTaste;
  22. using Newtonsoft.Json;
  23. using Newtonsoft.Json.Linq;
  24. using Npgsql.TypeHandlers.GeometricHandlers;
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Configuration;
  28. using System.Diagnostics;
  29. using System.IO;
  30. using System.Text.Json.Nodes;
  31. using System.Windows;
  32. using System.Windows.Markup;
  33. namespace ivf_tl_Control
  34. {
  35. public class AppData
  36. {
  37. public static AppData Instance = new Lazy<AppData>(() => new AppData(), LazyThreadSafetyMode.ExecutionAndPublication).Value;
  38. public int guanbiTime = 0, csTime = 120, houseVentNum = 10, houseVentPre = 20, houseVentWaitTimeB = 1500, houseVentWaitTimeD = 5000, houseAutoWaitTime = 10, houseCCDAutoWaitTime = 5, houseCCDError = 0, houseCCDFailedNumber = 3, houseCCDFailedWaitTime = 15, queuAir = 0;
  39. public event Action StopProEvent;
  40. public bool MvcTest { get; set; } = false;
  41. public string TakePhotoString = string.Empty;
  42. private AppData()
  43. {
  44. _urlIp = $"{ConfigurationManager.AppSettings["urlIp"]}:{ConfigurationManager.AppSettings["urlPort"]}/";
  45. kfkaIP = $"{ConfigurationManager.AppSettings["kfkaIP"]}:{ConfigurationManager.AppSettings["kfkaPort"]}";
  46. // M5-01-2 / R8:mqttIp/mqttPort 启动期容错读取,缺键不崩在构造里(mqttIp 缺键回退空串,mqttPort 缺键/非数回退 1883)。
  47. MqttIp = ConfigurationManager.AppSettings["mqttIp"] ?? string.Empty;
  48. MqttPort = int.TryParse(ConfigurationManager.AppSettings["mqttPort"], out int mqttPortVal) ? mqttPortVal : 1883;
  49. if (int.TryParse(ConfigurationManager.AppSettings["gbTime"].ToString(), out int newTime1)) guanbiTime = newTime1;
  50. if (int.TryParse(ConfigurationManager.AppSettings["csTime"].ToString(), out int newTime2)) csTime = newTime2;
  51. if (int.TryParse(ConfigurationManager.AppSettings["VentNum"].ToString(), out int newTime3)) houseVentNum = newTime3;
  52. if (int.TryParse(ConfigurationManager.AppSettings["VentPre"].ToString(), out int newTime4)) houseVentPre = newTime4;
  53. if (int.TryParse(ConfigurationManager.AppSettings["VentWaitTimeB"].ToString(), out int newTime5)) houseVentWaitTimeB = newTime5;
  54. if (int.TryParse(ConfigurationManager.AppSettings["VentWaitTimeD"].ToString(), out int newTime6)) houseVentWaitTimeD = newTime6;
  55. if (int.TryParse(ConfigurationManager.AppSettings["AutoWaitTime"].ToString(), out int newTime7)) houseAutoWaitTime = newTime7;
  56. if (int.TryParse(ConfigurationManager.AppSettings["CCDAutoWaitTime"].ToString(), out int newTime8)) houseCCDAutoWaitTime = newTime8;
  57. if (int.TryParse(ConfigurationManager.AppSettings["CCDError"].ToString(), out int newTime9)) houseCCDError = newTime9;
  58. if (int.TryParse(ConfigurationManager.AppSettings["CCDFailedNumber"].ToString(), out int newTime10)) houseCCDFailedNumber = newTime10;
  59. if (int.TryParse(ConfigurationManager.AppSettings["CCDFailedWaitTime"].ToString(), out int newTime11)) houseCCDFailedWaitTime = newTime11;
  60. if (int.TryParse(ConfigurationManager.AppSettings["QueuAir"].ToString(), out int newTime12)) queuAir = newTime12;
  61. TakePhotoString = GetLanguageStringByKey("D0010");
  62. //_urlIp = "http://gateway.aivfo.com:36000/";
  63. //MqttIp = "211.149.139.131";
  64. //MqttPort = 61883;
  65. //_urlIp = "http://test-gateway.aivfo.com:36000/";
  66. //MqttIp = "211.149.139.131";
  67. //MqttPort = 62883;
  68. ImageDTODic = new Dictionary<string, ImageDTO>();
  69. sqlitePath = $"{Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"DependFile\DB\aivfoTL.db")}";
  70. LogService = new LogServiceImpl() { Pan = "C" };
  71. HttpService = new HttpService(_urlIp);
  72. HttpService.ErrorLogEvent += LogService.TLLog;
  73. HttpService.ExceptionLogEvent += LogService.ExceptionLog;
  74. DBService = new DBService();
  75. DBService.ErrorLogEvent += LogService.TLLog;
  76. DBService.ExceptionLogEvent += LogService.ExceptionLog;
  77. DBService.StartDbService(sqlitePath);
  78. // M2-04 标定结果存储:calibration.json 真相源 + 镜像 house_autofocus_calibration。
  79. // JSON 路径走部署工作目录(DependFile\AutoFocus),不写死 autofocustool 测试外壳常量路径。
  80. // DbMirror 绑定到 DBService.SaveAutofocusCalibration(scene 0 upsert / 1 append);
  81. // 任一步骤异常 CalibrationStore 内部已吞掉并经 Log 记录,不崩对焦/采集线程。
  82. string calibJsonPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"DependFile\AutoFocus\calibration.json");
  83. AutofocusStore = new CalibrationStore
  84. {
  85. JsonPath = calibJsonPath,
  86. Source = "LOCAL_JSON",
  87. Log = msg => LogService.TLLog(msg, LogEnum.RunError),
  88. DbMirror = (tlSn, houseSn, wellSn, scene, focusZ, exposure, horizontalPulse, peakRatio, circleFound, centerOffsetPct, note, source) =>
  89. DBService.SaveAutofocusCalibration(tlSn, houseSn, wellSn, scene, focusZ, exposure, horizontalPulse, peakRatio, circleFound, centerOffsetPct, note, source),
  90. // M2-06 安全门降级:关闭本地对焦时按 scene=0 基准位置拍照,由此回调读基准 FocusZ。
  91. BaselineReader = (tlSn, houseSn, wellSn) => DBService.GetBaselineFocusZ(tlSn, houseSn, wellSn),
  92. };
  93. KafkaService = new KafkaService(kafkaTopic, kfkaIP);
  94. KafkaService.ErrorLogEvent += LogService.TLLog;
  95. KafkaService.ExceptionLogEvent += LogService.ExceptionLog;
  96. MqttService = new MqttService(MqttIp, MqttPort, MqttUserName, MqttPassword);
  97. MqttService.ErrorLogEvent += LogService.TLLog;
  98. MqttService.ExceptionLogEvent += LogService.ExceptionLog;
  99. MqttService.MessEvent += MqttMessage;
  100. MqttService.MqttAlarm += MqttAlarm;
  101. SerialBinController = new SerialBinController(HttpService, DBService);
  102. SerialBinController.LogEvent += LogService.TLLog;
  103. SerialBinController.ExceptionLogEvent += LogService.ExceptionLog;
  104. HouseBinController = new HouseBinController(HttpService, DBService);
  105. HouseBinController.LogEvent += LogService.TLLog;
  106. HouseBinController.ExceptionLogEvent += LogService.ExceptionLog;
  107. }
  108. public void TestEvent()
  109. {
  110. //string messageinfo = $"{GetLanguageStringByKey("D0007")}1{GetLanguageStringByKey("D0008")}";
  111. //MessageBox.Show(messageinfo);
  112. //string ss = GetLanguageStringByKey("D0001");
  113. //return;
  114. StopProEvent?.Invoke();
  115. }
  116. public string _urlIp = "http://192.168.31.89:10010/";
  117. //public string _urlIp = "http://gateway.aivfo.com:36000/";
  118. private string kafkaTopic = "jiangxuebingPicTestTopic";
  119. private string kfkaIP = "192.168.31.89:9092";
  120. private string MqttIp = "211.149.139.131";
  121. private int MqttPort = 1883;
  122. private string MqttUserName = "aivfo";
  123. private string MqttPassword = "aivfo";
  124. private string MqttClientId = "TL/DATA/tlSn";
  125. private string MqttTopicName = "TL/DATA/tlSn";
  126. private string sqlitePath = "";
  127. private bool isSetZiDong = false;
  128. public Dictionary<string, ImageDTO> ImageDTODic { get; set; }
  129. // ── M5-04-3:图片补传补强 ──
  130. // (a) 去重防重传:StartUpLoadImage 每 5s 重扫落盘目录,单文件一次上传可能跨多个 5s 周期(慢链/超时),
  131. // 用 in-flight 集合标记「正在上传」,重扫时跳过,避免同名文件被两轮并发重传(现 ImageDTODic lock 只护缓存)。
  132. private readonly HashSet<string> _uploadingFiles = new HashSet<string>();
  133. // (b) 断网累积兜底告警阈值:落盘待传数超过此值视为断网堆积,置位告警(只读暴露给监控/提示),不静默堆积。
  134. // [D10] 具体阈值留 M7 校准;此处为占位默认值。
  135. public int PendingImageAlarmThreshold { get; set; } = 500;
  136. // 断网累积告警状态(只读):true=待传堆积超阈值。供 GetMonitorSnapshot/断线提示呈现,不触发删图。
  137. public bool ImageBacklogAlarm { get; private set; }
  138. public int LastPendingImageCount { get; private set; }
  139. public SerialBinController SerialBinController { get; set; }
  140. public HouseBinController HouseBinController { get; set; }
  141. public ILogService LogService { get; set; }
  142. public HttpService HttpService { get; set; }
  143. public DBService DBService { get; set; }
  144. /// <summary>M2-04 标定结果存储入口(calibration.json 真相源 + house_autofocus_calibration 镜像)。</summary>
  145. public CalibrationStore AutofocusStore { get; set; }
  146. public KafkaService KafkaService { get; set; }
  147. public MqttService MqttService { get; set; }
  148. public UserInfo CurrentUser { get; set; }
  149. /// <summary>启动期坏舱清单(InitTL 写入;GetMonitorSnapshot 透出 /status;ReportStartupFaults 经 reportAlarm 闭环上报)。</summary>
  150. public List<HouseFault> StartupFaults { get; set; } = new List<HouseFault>();
  151. public TLSetting TLSetting;
  152. public HouseBin HouseBin1;
  153. public HouseBin HouseBin2;
  154. public HouseBin HouseBin3;
  155. public HouseBin HouseBin4;
  156. public HouseBin HouseBin5;
  157. public HouseBin HouseBin6;
  158. public HouseBin HouseBin7;
  159. public HouseBin HouseBin8;
  160. public HouseBin HouseBin9;
  161. public HouseBin HouseBin10;
  162. public BufferBottleBin BufferBottleBin;
  163. // ── M5-03-2:各链路「最后成功通讯时间」只读时间戳 ──
  164. // 仅在已有的成功分支里赋值(不改上报逻辑/不改报文),供 GetMonitorSnapshot 只读呈现「不假装实时」。
  165. // LastHttpOkAt 由 operate 侧 HTTP 轮询(M5-04-4)写入,control 这里只持有/透传。
  166. public DateTime? LastMqttOkAt { get; private set; }
  167. public DateTime? LastKafkaOkAt { get; private set; }
  168. public DateTime? LastHttpOkAt { get; set; }
  169. /// <summary>
  170. /// M5-03-1:聚合 control 内存/事件的当前状态为只读快照(需求 7/10)。
  171. /// 纯读取 + 拷贝到值类型 DTO,不修改任何 control 状态、不暴露可写引用,监控页据此只读呈现。
  172. /// 任一字段取值异常被吞掉(监控页不应因取数失败而崩),缺失项以默认值呈现。
  173. /// </summary>
  174. public MonitorSnapshot GetMonitorSnapshot()
  175. {
  176. var snap = new MonitorSnapshot { SnapshotAt = DateTime.Now, ControlHosted = true };
  177. try
  178. {
  179. // MQTT 连接态(来源 MqttService.MqttIsConnected())
  180. try { snap.MqttConnected = MqttService != null && MqttService.MqttIsConnected(); } catch { snap.MqttConnected = false; }
  181. snap.LastMqttOkAt = LastMqttOkAt;
  182. try { snap.MqttLastConnectedAt = MqttService?.LastConnectedAt; } catch { }
  183. try { snap.MqttLastDisconnectedAt = MqttService?.LastDisconnectedAt; } catch { }
  184. snap.LastKafkaOkAt = LastKafkaOkAt;
  185. snap.LastHttpOkAt = LastHttpOkAt;
  186. // 服务器接口基址(脱敏展示,仅地址不含凭据)
  187. snap.ServerUrl = _urlIp;
  188. // 上传队列:内存缓存数 + 落盘目录待传数
  189. try { lock (ImageDTODic) snap.ImageCacheCount = ImageDTODic == null ? 0 : ImageDTODic.Count; } catch { }
  190. try { snap.PendingDiskImageCount = CountPendingDiskImages(); } catch { }
  191. snap.ImageBacklogAlarm = ImageBacklogAlarm;
  192. snap.PendingImageAlarmThreshold = PendingImageAlarmThreshold;
  193. // 磁盘(来源 GetDiskInfo(缓存盘))
  194. try
  195. {
  196. string pan = TLSetting != null && !string.IsNullOrEmpty(TLSetting.tmpDir) ? TLSetting.tmpDir : PathHelper.pan;
  197. if (!string.IsNullOrEmpty(pan))
  198. {
  199. var disk = GetDiskInfo(pan);
  200. snap.DiskPath = disk.diskPath;
  201. snap.DiskExist = disk.diskExist == 0;
  202. snap.DiskFreeGb = disk.diskSpace;
  203. }
  204. }
  205. catch { }
  206. // 各舱室只读态
  207. var bins = new HouseBin[] { HouseBin1, HouseBin2, HouseBin3, HouseBin4, HouseBin5, HouseBin6, HouseBin7, HouseBin8, HouseBin9, HouseBin10 };
  208. int sn = 0;
  209. foreach (var bin in bins)
  210. {
  211. sn++;
  212. if (bin == null) continue;
  213. try
  214. {
  215. snap.Houses.Add(new HouseMonitorRow
  216. {
  217. HouseSn = sn,
  218. PortName = bin.PortName,
  219. RunState = bin.RunState,
  220. Temperature = bin.Temperature,
  221. Pressure = bin.Pressure,
  222. HouseState = bin.IsDoorOpen.ToString(),
  223. ComState = bin.ComBin != null ? "已连接" : "未连接",
  224. CcdState = bin.CCDError ? "异常" : "正常",
  225. CcdError = bin.CCDError,
  226. // 阶段2 §6 三块补充(只读)
  227. WorkingType = bin.WorkingType.ToString(),
  228. ValveState = bin.ValveState.ToString(),
  229. CapturePausedByGate = bin.CapturePausedByGate,
  230. });
  231. }
  232. catch { }
  233. }
  234. }
  235. catch (Exception ex)
  236. {
  237. ExLog(ex, "GetMonitorSnapshot");
  238. }
  239. // 舱故障透出(StartupFaults → HouseFaultRow,字符串化枚举跨端);独立 try,不影响其余快照。
  240. try
  241. {
  242. snap.Faults = (StartupFaults ?? new List<HouseFault>())
  243. .Select(f => new HouseFaultRow
  244. {
  245. HouseSn = f.HouseSn,
  246. FaultType = f.Type.ToString(),
  247. Reason = f.Reason,
  248. Stage = f.Stage,
  249. At = f.At,
  250. Isolated = f.Isolated
  251. }).ToList();
  252. }
  253. catch { }
  254. return snap;
  255. }
  256. /// <summary>落盘目录(自动对焦 + CCD)待传 *.jpg 计数(只读,不删不改)。</summary>
  257. private int CountPendingDiskImages()
  258. {
  259. int count = 0;
  260. try
  261. {
  262. string autoPath = PathHelper.GetAutoFocusSaveDirectory();
  263. if (Directory.Exists(autoPath)) count += Directory.GetFiles(autoPath, "*.jpg").Length;
  264. }
  265. catch { }
  266. try
  267. {
  268. string ccdPath = PathHelper.GetEmbryoPicSaveDirectory();
  269. if (Directory.Exists(ccdPath)) count += Directory.GetFiles(ccdPath, "*.jpg").Length;
  270. }
  271. catch { }
  272. return count;
  273. }
  274. private void ExLog(Exception ex, string name)
  275. {
  276. LogService.ExceptionLog(ex, $"AppData.{name}", null, LogEnum.RunException);
  277. }
  278. public bool Login(string _account, string _password)
  279. {
  280. try
  281. {
  282. CurrentUser = HttpService.Login(_account, _password);
  283. return CurrentUser != null;
  284. }
  285. catch (Exception ex)
  286. {
  287. ExLog(ex, "Login");
  288. return false;
  289. }
  290. }
  291. /// <summary>
  292. /// 开启kafka、mqtt、历史记录上报
  293. /// </summary>
  294. /// <returns></returns>
  295. public async Task StartAsync()
  296. {
  297. KafkaService.KafkaSetNameAndIp(TLSetting.kafkaTopic, kfkaIP);
  298. var kafkaSuccess = await KafkaService.CreateTopicAsync(3);
  299. if (kafkaSuccess)
  300. {
  301. if (!MvcTest) StartUpLoadImage();
  302. }
  303. else
  304. {
  305. LogService.TLLog($"kafka创建分区失败", LogEnum.RunError);
  306. }
  307. MqttClientId = $"TL/DATA/{TLSetting.tlSn}";
  308. MqttService.StartMqtt(TLSetting.mqttQueue, MqttClientId);
  309. StartSendMqttMsg();
  310. StartSendHistoryMsg();
  311. StartPushMessageThread();
  312. Task.Run(() => DeleteLog());
  313. }
  314. /// <summary>
  315. /// 重启kafka、mqtt
  316. /// </summary>
  317. private void UpdataKafkaAndMqtt()
  318. {
  319. if (KafkaService.KafkaSetNameAndIp(TLSetting.kafkaTopic, kfkaIP))
  320. {
  321. var kafkaSuccess = KafkaService.CreateTopicAsync(3).Result;
  322. if (!kafkaSuccess)
  323. {
  324. LogService.TLLog($"kafka创建分区失败", LogEnum.RunError);
  325. }
  326. }
  327. if (!MqttService.IsXiangTong(TLSetting.mqttQueue, $"TL/DATA/{TLSetting.tlSn}"))
  328. {
  329. MqttService.IsDispose = true;
  330. MqttService = new MqttService(MqttIp, MqttPort, MqttUserName, MqttPassword);
  331. MqttService.ErrorLogEvent += LogService.TLLog;
  332. MqttService.ExceptionLogEvent += LogService.ExceptionLog;
  333. MqttService.MessEvent += MqttMessage;
  334. MqttClientId = $"TL/DATA/{TLSetting.tlSn}";
  335. MqttService.StartMqtt(TLSetting.mqttQueue, MqttClientId);
  336. }
  337. }
  338. /// <summary>
  339. /// 开启图片上传线程
  340. /// </summary>
  341. public void StartUpLoadImage()
  342. {
  343. LogService.TLLog($"开始运行kafka线程", LogEnum.KafkaRecord);
  344. Task.Factory.StartNew(async () =>
  345. {
  346. while (true)
  347. {
  348. try
  349. {
  350. string autoPath = PathHelper.GetAutoFocusSaveDirectory();
  351. if (Directory.Exists(autoPath))
  352. {
  353. var autoFileList = Directory.GetFiles(autoPath, "*.jpg");
  354. foreach (var item in autoFileList)
  355. {
  356. await KafkaUploadImageAsync(item);
  357. }
  358. }
  359. string ccdPath = PathHelper.GetEmbryoPicSaveDirectory();
  360. if (Directory.Exists(ccdPath))
  361. {
  362. var ccdFileList = Directory.GetFiles(ccdPath, "*.jpg");
  363. foreach (var item in ccdFileList)
  364. {
  365. await KafkaUploadImageAsync(item);
  366. }
  367. }
  368. // M5-04-3(b):断网累积兜底——每轮重扫后统计落盘待传数,超阈值置位告警(只读,供监控/断线提示)。
  369. // 不删图、不丢图,只把「堆积」显性暴露,避免静默撑爆磁盘(配合 M5-03 磁盘水位)。
  370. try
  371. {
  372. int pending = CountPendingDiskImages();
  373. LastPendingImageCount = pending;
  374. bool backlog = pending > PendingImageAlarmThreshold;
  375. if (backlog && !ImageBacklogAlarm)
  376. LogService.TLLog($"图片待传堆积告警:落盘待传 {pending} 张已超阈值 {PendingImageAlarmThreshold},疑似上传链路断开", LogEnum.RunError);
  377. ImageBacklogAlarm = backlog;
  378. }
  379. catch { }
  380. await Task.Delay(1000 * 5);
  381. }
  382. catch (Exception ex)
  383. {
  384. LogService.ExceptionLog(ex, "上传图片", null, LogEnum.RunException);
  385. }
  386. }
  387. }, TaskCreationOptions.LongRunning);
  388. }
  389. /// <summary>
  390. /// 开启mqtt消息上报线程
  391. /// </summary>
  392. public void StartSendMqttMsg()
  393. {
  394. LogService.TLLog($"Mqtt开始上报", LogEnum.MqttClient);
  395. Task.Factory.StartNew(async () =>
  396. {
  397. while (true)
  398. {
  399. try
  400. {
  401. if (!MqttService.MqttIsConnected())
  402. {
  403. await Task.Delay(3000);
  404. continue;
  405. }
  406. List<HouseMqttData> houseMqttDataList = new List<HouseMqttData>();
  407. var a = GetHouseMqttData(HouseBin1);
  408. if (a != null) houseMqttDataList.Add(a);
  409. a = GetHouseMqttData(HouseBin2);
  410. if (a != null) houseMqttDataList.Add(a);
  411. a = GetHouseMqttData(HouseBin3);
  412. if (a != null) houseMqttDataList.Add(a);
  413. a = GetHouseMqttData(HouseBin4);
  414. if (a != null) houseMqttDataList.Add(a);
  415. a = GetHouseMqttData(HouseBin5);
  416. if (a != null) houseMqttDataList.Add(a);
  417. a = GetHouseMqttData(HouseBin6);
  418. if (a != null) houseMqttDataList.Add(a);
  419. a = GetHouseMqttData(HouseBin7);
  420. if (a != null) houseMqttDataList.Add(a);
  421. a = GetHouseMqttData(HouseBin8);
  422. if (a != null) houseMqttDataList.Add(a);
  423. a = GetHouseMqttData(HouseBin9);
  424. if (a != null) houseMqttDataList.Add(a);
  425. a = GetHouseMqttData(HouseBin10);
  426. if (a != null) houseMqttDataList.Add(a);
  427. a = GetHouseMqttData(BufferBottleBin);
  428. if (a != null) houseMqttDataList.Add(a);
  429. if (houseMqttDataList.Any() && MqttService.MqttIsConnected())
  430. {
  431. string mqttMsg = JsonConvert.SerializeObject(houseMqttDataList);
  432. await MqttService.PublishAsync(mqttMsg);
  433. LastMqttOkAt = DateTime.Now; // M5-03-2:MQTT 上报成功时间戳(只读监控用,不改上报逻辑)
  434. }
  435. await Task.Delay(1000);
  436. }
  437. catch (Exception ex)
  438. {
  439. LogService.ExceptionLog(ex, "实时数据上报", null, LogEnum.RunException);
  440. }
  441. }
  442. }, TaskCreationOptions.LongRunning);
  443. }
  444. /// <summary>
  445. /// 开启仓时历史记录上报线程
  446. /// </summary>
  447. public void StartSendHistoryMsg()
  448. {
  449. LogService.TLLog($"开启仓时历史记录上报线程", LogEnum.KafkaRecord);
  450. Task.Factory.StartNew(async () =>
  451. {
  452. await Task.Delay(1000 * 60);
  453. List<HouseHistoryData> houseMqttDataList = new List<HouseHistoryData>();
  454. HouseHistoryData a = null;
  455. while (true)
  456. {
  457. try
  458. {
  459. //只上报缓冲瓶的历史记录
  460. houseMqttDataList.Clear();
  461. a = GetHouseHistoryData(BufferBottleBin);
  462. if (a != null) houseMqttDataList.Add(a);
  463. if (houseMqttDataList.Any()) SerialBinController.ReportDataController(JsonConvert.SerializeObject(houseMqttDataList));
  464. //List<HouseHistoryData> houseMqttDataList = new List<HouseHistoryData>();
  465. //var a = GetHouseHistoryData(HouseBin1);
  466. //if (a != null) houseMqttDataList.Add(a);
  467. //a = GetHouseHistoryData(HouseBin2);
  468. //if (a != null) houseMqttDataList.Add(a);
  469. //a = GetHouseHistoryData(HouseBin3);
  470. //if (a != null) houseMqttDataList.Add(a);
  471. //a = GetHouseHistoryData(HouseBin4);
  472. //if (a != null) houseMqttDataList.Add(a);
  473. //a = GetHouseHistoryData(HouseBin5);
  474. //if (a != null) houseMqttDataList.Add(a);
  475. //a = GetHouseHistoryData(HouseBin6);
  476. //if (a != null) houseMqttDataList.Add(a);
  477. //a = GetHouseHistoryData(HouseBin7);
  478. //if (a != null) houseMqttDataList.Add(a);
  479. //a = GetHouseHistoryData(HouseBin8);
  480. //if (a != null) houseMqttDataList.Add(a);
  481. //a = GetHouseHistoryData(HouseBin9);
  482. //if (a != null) houseMqttDataList.Add(a);
  483. //a = GetHouseHistoryData(HouseBin10);
  484. //if (a != null) houseMqttDataList.Add(a);
  485. //a = GetHouseHistoryData(BufferBottleBin);
  486. //if (a != null) houseMqttDataList.Add(a);
  487. //if (houseMqttDataList.Any())
  488. //{
  489. // string mqttMsg = JsonConvert.SerializeObject(houseMqttDataList);
  490. // SerialBinController.ReportDataController(mqttMsg);
  491. //}
  492. //await Task.Delay(1000 * TLSetting.historyCurveInterval);
  493. }
  494. catch (Exception ex)
  495. {
  496. LogService.ExceptionLog(ex, "仓时历史记录上报", null, LogEnum.RunException);
  497. }
  498. finally
  499. {
  500. await Task.Delay(1000 * TLSetting.historyCurveInterval);
  501. }
  502. }
  503. }, TaskCreationOptions.LongRunning);
  504. }
  505. /// <summary>
  506. /// 开启心跳线程
  507. /// </summary>
  508. public void StartPushMessageThread()
  509. {
  510. int time = 1000 * 60 * 10;
  511. Task.Factory.StartNew(() =>
  512. {
  513. while (true)
  514. {
  515. try
  516. {
  517. SerialBinController.PushMessageController(TLSetting.tlSn, 1, GetDiskInfo(TLSetting.tmpDir));
  518. if (DateTime.Now.Hour != TLSetting.autoFocusTime)
  519. {
  520. if (isSetZiDong) isSetZiDong = false;
  521. continue;
  522. }
  523. if (isSetZiDong) continue;
  524. Task.Run(() => DeleteLog());
  525. Task.Run(() => CleanAutofocusCalibration()); // G4-1:每日维护窗口同步清理对焦标定 scene=1 过期记录
  526. isSetZiDong = true;
  527. if (HouseBin1 != null)
  528. {
  529. HouseBin1.FirstClearest = true;
  530. HouseBin1.ReCa = true;
  531. }
  532. if (HouseBin2 != null)
  533. {
  534. HouseBin2.FirstClearest = true;
  535. HouseBin2.ReCa = true;
  536. }
  537. if (HouseBin3 != null)
  538. {
  539. HouseBin3.FirstClearest = true;
  540. HouseBin3.ReCa = true;
  541. }
  542. if (HouseBin4 != null)
  543. {
  544. HouseBin4.FirstClearest = true;
  545. HouseBin4.ReCa = true;
  546. }
  547. if (HouseBin5 != null)
  548. {
  549. HouseBin5.FirstClearest = true;
  550. HouseBin5.ReCa = true;
  551. }
  552. if (HouseBin6 != null)
  553. {
  554. HouseBin6.FirstClearest = true;
  555. HouseBin6.ReCa = true;
  556. }
  557. if (HouseBin7 != null)
  558. {
  559. HouseBin7.FirstClearest = true;
  560. HouseBin7.ReCa = true;
  561. }
  562. if (HouseBin8 != null)
  563. {
  564. HouseBin8.FirstClearest = true;
  565. HouseBin8.ReCa = true;
  566. }
  567. if (HouseBin9 != null)
  568. {
  569. HouseBin9.FirstClearest = true;
  570. HouseBin9.ReCa = true;
  571. }
  572. if (HouseBin10 != null)
  573. {
  574. HouseBin10.FirstClearest = true;
  575. HouseBin10.ReCa = true;
  576. }
  577. }
  578. catch (Exception ex)
  579. {
  580. LogService.ExceptionLog(ex, "心跳线程", null, LogEnum.RunException);
  581. }
  582. finally
  583. {
  584. Thread.Sleep(time);
  585. }
  586. }
  587. }, TaskCreationOptions.LongRunning);
  588. }
  589. #region 仓室事件设置
  590. /// <summary>
  591. /// 仓室事件初始化
  592. /// </summary>
  593. /// <param name="BufferBottleBin"></param>
  594. public void InitHouseBinEvent(HouseBin houseBin)
  595. {
  596. houseBin.TLLogEvent += LogService.TLLog;
  597. houseBin.HouseLogEvent += LogService.HouseLog;
  598. houseBin.ExceptionLogEvent += LogService.ExceptionLog;
  599. houseBin.GetAutoFocusServiceEvent += HouseBin_GetAutoFocusServiceEvent;
  600. houseBin.GetAutoFocusDBEvent += HouseBin_GetAutoFocusDBEvent;
  601. // M2-04:注入标定结果存储入口(写 JSON 真相源 + 镜像库),对焦逐 well 标定后调用。
  602. houseBin.AutofocusStore = AutofocusStore;
  603. houseBin.GetCCDServiceEvent += HouseBin_GetCCDServiceEvent;
  604. houseBin.GetCCDDBEvent += HouseBin_GetCCDDBEvent;
  605. houseBin.UploadImageEvent += HouseBin_UploadImageEvent;
  606. houseBin.UpdateAutofocusStateEvent += HouseBin_UpdateAutofocusStateEvent;
  607. houseBin.SavePicDbEvent += HouseBin_SavePicDbEvent;
  608. houseBin.HouseStateEvent += HouseBin_HouseStateEvent;
  609. houseBin.CCDStateEvent += HouseBinPhotoStateEvent;
  610. houseBin.OnHistoryEvent += HouseBin_OnHistoryEvent;
  611. houseBin.ChangeBufferBottleBinEvent += HouseBin_ChangeBufferBottleBinEvent;
  612. houseBin.HouseBinChangeBufferBottleBinEvent += HouseBin_HouseBinChangeBufferBottleBinEvent;
  613. //houseBin.CCDStateEvent += HouseBin_CCDStateEvent;
  614. houseBin.TongQi = csTime * 1000;
  615. houseBin.VentPre = houseVentPre;
  616. houseBin.VentNum = houseVentNum;
  617. houseBin.VentWaitTimeB = houseVentWaitTimeB;
  618. houseBin.VentWaitTimeD = houseVentWaitTimeD;
  619. houseBin.AutoWaitTime = houseAutoWaitTime * 60000;
  620. houseBin.CCDAutoWaitTime = houseCCDAutoWaitTime * 60000;
  621. houseBin.CCDFailedNumber = houseCCDFailedNumber;
  622. houseBin.CCDFailedWaitTime = houseCCDFailedWaitTime * 1000;
  623. if (houseCCDError == 1)
  624. {
  625. houseBin.CCDError = true;
  626. }
  627. else
  628. {
  629. houseBin.CCDError = false;
  630. }
  631. if (queuAir == 0)
  632. {
  633. houseBin.IsPai = false;
  634. }
  635. else
  636. {
  637. houseBin.IsPai = true;
  638. }
  639. houseBin.TakePhotoFailed = TakePhotoString;
  640. }
  641. private void HouseBin_CCDStateEvent(int houseSn, int ccdState)
  642. {
  643. if (ccdState == 1)
  644. {
  645. LogService.TLLog($"{houseSn}号舱室拍照异常,停止拍照", LogEnum.RunRecord);
  646. }
  647. else
  648. {
  649. LogService.TLLog($"{houseSn}号舱室拍照恢复正常", LogEnum.RunRecord);
  650. }
  651. }
  652. private bool HouseBin_HouseBinChangeBufferBottleBinEvent(HouseBin arg1, int arg2)
  653. {
  654. if (BufferBottleBin == null)
  655. {
  656. LogService.TLLog($"缓冲瓶为空,无法操作进气阀:{arg1}、{arg2}", LogEnum.RunError);
  657. return false;
  658. }
  659. if (arg2 == 0)
  660. {
  661. BufferBottleBin.HuanQiEnd(arg1);
  662. return true;
  663. }
  664. else if (arg2 == 1)
  665. {
  666. BufferBottleBin.HuanQiStart(arg1);
  667. return true;
  668. }
  669. else
  670. {
  671. LogService.TLLog($"状态码错误,无法操作进气阀:{arg1}、{arg2}", LogEnum.RunError);
  672. return false;
  673. }
  674. }
  675. private bool HouseBin_ChangeBufferBottleBinEvent(int arg1, int arg2)
  676. {
  677. if (BufferBottleBin == null)
  678. {
  679. LogService.TLLog($"缓冲瓶为空,无法操作进气阀:{arg1}、{arg2}", LogEnum.RunError);
  680. return false;
  681. }
  682. if (arg2 == 0)
  683. {
  684. BufferBottleBin.CloseIntakeValve(arg1);
  685. return true;
  686. }
  687. else if (arg2 == 1)
  688. {
  689. BufferBottleBin.OpenIntakeValve(arg1);
  690. return true;
  691. }
  692. else
  693. {
  694. LogService.TLLog($"状态码错误,无法操作进气阀:{arg1}、{arg2}", LogEnum.RunError);
  695. return false;
  696. }
  697. }
  698. private void HouseBin_OnHistoryEvent(HouseHistoryData obj)
  699. {
  700. SerialBinController.ReportDataController(JsonConvert.SerializeObject(new List<HouseHistoryData> { obj }));
  701. }
  702. private void HouseBin_HouseStateEvent(int housesn, int houseState, int comState, int photoState, int wellSN, int airSwapState)
  703. {
  704. SerialBinController.ReportAlarmController(TLSetting.tlSn, housesn, houseState, comState, photoState, wellSN, airSwapState);
  705. //if (photoState != 0)
  706. //{
  707. // SerialBinController.ReportAlarmController(TLSetting.tlSn, housesn, houseState, comState, photoState, wellSN, airSwapState);
  708. // return;
  709. //}
  710. //for (int i = 1; i <= 16; i++)
  711. //{
  712. // SerialBinController.ReportAlarmController(TLSetting.tlSn, housesn, houseState, comState, photoState, i, airSwapState);
  713. //}
  714. }
  715. private void HouseBinPhotoStateEvent(int housesn, int photoState, int wellSN)
  716. {
  717. if (photoState != 0)
  718. {
  719. SerialBinController.ReportAlarmController(TLSetting.tlSn, housesn, -1, -1, photoState, wellSN, -1);
  720. StopProEvent?.Invoke();
  721. return;
  722. }
  723. for (int i = 1; i <= 16; i++)
  724. {
  725. SerialBinController.ReportAlarmController(TLSetting.tlSn, housesn, -1, -1, photoState, i, -1);
  726. }
  727. }
  728. /// <summary>
  729. /// 仓室图片保存到数据库
  730. /// </summary>
  731. /// <param name="obj"></param>
  732. /// <exception cref="NotImplementedException"></exception>
  733. private void HouseBin_SavePicDbEvent(ImageDTO obj)
  734. {
  735. if (obj == null) return;
  736. SerialBinController.SavePictreController(obj);
  737. }
  738. /// <summary>
  739. /// 仓室上传图片
  740. /// </summary>
  741. /// <param name="obj"></param>
  742. private void HouseBin_UploadImageEvent(ImageDTO obj)
  743. {
  744. if (obj == null) return;
  745. lock (ImageDTODic)
  746. {
  747. if (ImageDTODic.Count > 50)
  748. {
  749. LogService.TLLog($"内存当中保存的图片已经超过50张了{obj.HouseSn}、{obj.WellSn}、{obj.SourceImageName}", LogEnum.RunError);
  750. return;
  751. }
  752. if (!ImageDTODic.ContainsKey(obj.SourceImageName))
  753. {
  754. ImageDTODic.Add(obj.SourceImageName, obj);
  755. }
  756. }
  757. }
  758. /// <summary>
  759. /// 从服务器获取自动对焦位置
  760. /// </summary>
  761. /// <param name="arg1"></param>
  762. /// <param name="arg2"></param>
  763. /// <param name="arg3"></param>
  764. /// <returns></returns>
  765. private List<HouseWellPhoto> HouseBin_GetAutoFocusServiceEvent(int arg1, Dictionary<int, DateTime?> arg3)
  766. {
  767. List<WellSnAndAutoTime> wellSnAndAutoTimes = new List<WellSnAndAutoTime>();
  768. foreach (var item in arg3)
  769. {
  770. wellSnAndAutoTimes.Add(new WellSnAndAutoTime
  771. {
  772. well = item.Key,
  773. autofocusTime = item.Value.HasValue ? item.Value.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
  774. });
  775. }
  776. PositionRequestDTO positionRequestDTO = new PositionRequestDTO()
  777. {
  778. houseSn = arg1,
  779. tlSn = TLSetting.tlSn,
  780. wellSnList = wellSnAndAutoTimes,
  781. };
  782. return HouseBinController.GetAutoFocusController(positionRequestDTO);
  783. }
  784. /// <summary>
  785. /// 从数据库获取自动对焦位置
  786. /// </summary>
  787. /// <param name="arg1"></param>
  788. /// <param name="arg2"></param>
  789. /// <param name="arg3"></param>
  790. /// <returns></returns>
  791. private List<HouseWellPhoto> HouseBin_GetAutoFocusDBEvent(int arg1, Dictionary<int, DateTime?> arg3)
  792. {
  793. List<WellSnAndAutoTime> wellSnAndAutoTimes = new List<WellSnAndAutoTime>();
  794. foreach (var item in arg3)
  795. {
  796. wellSnAndAutoTimes.Add(new WellSnAndAutoTime
  797. {
  798. well = item.Key,
  799. autofocusTime = item.Value.HasValue ? item.Value.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
  800. });
  801. }
  802. PositionRequestDTO positionRequestDTO = new PositionRequestDTO()
  803. {
  804. houseSn = arg1,
  805. tlSn = TLSetting.tlSn,
  806. wellSnList = wellSnAndAutoTimes,
  807. };
  808. return HouseBinController.DbGetPositionData(positionRequestDTO.wellSnList.Select(x => x.well).ToList(), positionRequestDTO.houseSn, positionRequestDTO.tlSn, 0);
  809. }
  810. /// <summary>
  811. /// 服务器获取仓室拍照位置
  812. /// </summary>
  813. /// <param name="arg1"></param>
  814. /// <param name="arg2"></param>
  815. /// <param name="arg3"></param>
  816. /// <returns></returns>
  817. private PositionInfoResultDTO HouseBin_GetCCDServiceEvent(int arg1, Dictionary<int, DateTime?> arg3)
  818. {
  819. List<WellSnAndAutoTime> wellSnAndAutoTimes = new List<WellSnAndAutoTime>();
  820. foreach (var item in arg3)
  821. {
  822. wellSnAndAutoTimes.Add(new WellSnAndAutoTime
  823. {
  824. well = item.Key,
  825. autofocusTime = item.Value.HasValue ? item.Value.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
  826. });
  827. }
  828. PositionRequestDTO positionRequestDTO = new PositionRequestDTO()
  829. {
  830. houseSn = arg1,
  831. wellSnList = wellSnAndAutoTimes,
  832. tlSn = TLSetting.tlSn,
  833. };
  834. var result = HouseBinController.GetCCDPositionController(positionRequestDTO);
  835. if (result != null && result.complete == 0)//完成
  836. {
  837. List<HouseWellPhoto> CCDPositionList = new List<HouseWellPhoto>();
  838. foreach (var item in result.positionVOList)
  839. {
  840. CCDPositionList.Add(ConvertHelper.ConvertToHouseWellPhoto(item));
  841. }
  842. HouseBinController.DbUpdatePositionData(CCDPositionList, positionRequestDTO.houseSn, positionRequestDTO.tlSn, 1);
  843. }
  844. return result;
  845. }
  846. /// <summary>
  847. /// 数据库获取仓室拍照位置
  848. /// </summary>
  849. /// <param name="arg1"></param>
  850. /// <param name="arg2"></param>
  851. /// <param name="arg3"></param>
  852. /// <returns></returns>
  853. private List<HouseWellPhoto> HouseBin_GetCCDDBEvent(int arg1, Dictionary<int, DateTime?> arg3)
  854. {
  855. List<WellSnAndAutoTime> wellSnAndAutoTimes = new List<WellSnAndAutoTime>();
  856. foreach (var item in arg3)
  857. {
  858. wellSnAndAutoTimes.Add(new WellSnAndAutoTime
  859. {
  860. well = item.Key,
  861. autofocusTime = item.Value.HasValue ? item.Value.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
  862. });
  863. }
  864. PositionRequestDTO positionRequestDTO = new PositionRequestDTO()
  865. {
  866. houseSn = arg1,
  867. wellSnList = wellSnAndAutoTimes,
  868. tlSn = TLSetting.tlSn,
  869. };
  870. return HouseBinController.DbGetPositionData(positionRequestDTO.wellSnList.Select(x => x.well).ToList(), positionRequestDTO.houseSn, positionRequestDTO.tlSn, 1);
  871. }
  872. private void HouseBin_UpdateAutofocusStateEvent(bool newValue, int housesn)
  873. {
  874. int autoFocus = 0;
  875. if (newValue)
  876. {
  877. autoFocus = 1;
  878. }
  879. SerialBinController.UpdateAutofocusStateController(TLSetting.tlSn, housesn, autoFocus);
  880. }
  881. /// <summary>
  882. /// 缓冲瓶事件初始化
  883. /// </summary>
  884. /// <param name="BufferBottleBin"></param>
  885. public void InitBufferBottleBinEvent(BufferBottleBin BufferBottleBin)
  886. {
  887. BufferBottleBin.TLLogEvent += LogService.TLLog;
  888. BufferBottleBin.HouseLogEvent += LogService.HouseLog;
  889. BufferBottleBin.ExceptionLogEvent += LogService.ExceptionLog;
  890. BufferBottleBin.HouseStateEvent += HouseBin_HouseStateEvent;
  891. }
  892. #endregion
  893. #region mqtt消息处理
  894. /// <summary>
  895. /// mqtt接受消息
  896. /// </summary>
  897. /// <param name="message"></param>
  898. public void MqttMessage(string message)
  899. {
  900. if (string.IsNullOrEmpty(message)) return;
  901. MqttResult mqttResult = null;
  902. bool isSuccess = true;
  903. string uuid = null;
  904. try
  905. {
  906. mqttResult = JsonConvert.DeserializeObject<MqttResult>(message);
  907. if (mqttResult == null)
  908. {
  909. LogService.TLLog($"AppData.MqttMessage,mqtt消息反序列化失败,消息:{message}", LogEnum.MqttClient);
  910. return;
  911. }
  912. switch (mqttResult.type)
  913. {
  914. case (int)MqttEnum.StartBalance:
  915. isSuccess = StartBalance(mqttResult.data);
  916. break;
  917. case (int)MqttEnum.EndBalance:
  918. isSuccess = EndBalance(mqttResult.data);
  919. break;
  920. case (int)MqttEnum.StartDish:
  921. isSuccess = StartDish(mqttResult.data);
  922. break;
  923. case (int)MqttEnum.EndDish:
  924. isSuccess = EndDish(mqttResult.data);
  925. break;
  926. case (int)MqttEnum.EmbryoState:
  927. isSuccess = EmbryoState(mqttResult.data);
  928. break;
  929. case (int)MqttEnum.Update:
  930. isSuccess = UpDataSettingMqtt(mqttResult.data);
  931. break;
  932. case (int)MqttEnum.DebugStart:
  933. isSuccess = DebugStart(mqttResult.data, ref uuid);
  934. break;
  935. case (int)MqttEnum.HouseAutoFocus:
  936. isSuccess = HouseAutoFocus(mqttResult.data);
  937. break;
  938. case (int)MqttEnum.WellAutoFocus:
  939. isSuccess = WellAutoFocus(mqttResult.data);
  940. break;
  941. }
  942. }
  943. catch (Exception ex)
  944. {
  945. LogService.ExceptionLog(ex, "mqtt消息处理", null, LogEnum.RunException);
  946. isSuccess = false;
  947. }
  948. finally
  949. {
  950. if (mqttResult != null)
  951. {
  952. if (string.IsNullOrEmpty(uuid))
  953. {
  954. SerialBinController.MqttResultController(isSuccess ? 200 : 400, isSuccess, mqttResult.messageId);
  955. }
  956. else
  957. {
  958. SerialBinController.MqttResultController(isSuccess ? 200 : 400, isSuccess, mqttResult.messageId, uuid);
  959. }
  960. }
  961. }
  962. }
  963. /// <summary>
  964. /// 开始平衡
  965. /// </summary>
  966. /// <param name="data"></param>
  967. /// <returns></returns>
  968. private bool StartBalance(object data)
  969. {
  970. try
  971. {
  972. Balance balance = JsonConvert.DeserializeObject<Balance>(data.ToString());
  973. DBService.AddBalance(balance);
  974. HouseBin currentHouseBin = HouseSnToHouseBin(balance.houseSn);
  975. if (currentHouseBin == null) return false;
  976. currentHouseBin.StartBlance(balance);
  977. return true;
  978. }
  979. catch (Exception ex)
  980. {
  981. ExLog(ex, "StartBalance");
  982. return false;
  983. }
  984. }
  985. private bool EndBalance(object data)
  986. {
  987. try
  988. {
  989. Balance balance = JsonConvert.DeserializeObject<Balance>(data.ToString());
  990. HouseBin currentHouseBin = HouseSnToHouseBin(balance.houseSn);
  991. if (currentHouseBin == null) return false;
  992. DBService.EndBalance(balance.id, balance.endTime);
  993. currentHouseBin.StopBlance();
  994. return true;
  995. }
  996. catch (Exception ex)
  997. {
  998. ExLog(ex, "EndBalance");
  999. return false;
  1000. }
  1001. }
  1002. private bool StartDish(object data)
  1003. {
  1004. try
  1005. {
  1006. Dish dish = JsonConvert.DeserializeObject<Dish>(data.ToString());
  1007. DBService.AddDish(dish, dish.tlSn);
  1008. HouseBin currentHouseBin = HouseSnToHouseBin(dish.houseSn);
  1009. if (currentHouseBin == null) return false;
  1010. currentHouseBin.StartDish(dish);
  1011. return true;
  1012. }
  1013. catch (Exception ex)
  1014. {
  1015. ExLog(ex, "StartDish");
  1016. return false;
  1017. }
  1018. }
  1019. private bool EndDish(object data)
  1020. {
  1021. try
  1022. {
  1023. Dish dish = JsonConvert.DeserializeObject<Dish>(data.ToString());
  1024. DBService.EndDish(dish.id, dish.endTime.Value, dish.tlSn);
  1025. HouseBin currentHouseBin = HouseSnToHouseBin(dish.houseSn);
  1026. if (currentHouseBin == null) return false;
  1027. currentHouseBin.StopDish();
  1028. return true;
  1029. }
  1030. catch (Exception ex)
  1031. {
  1032. ExLog(ex, "EndDish");
  1033. return false;
  1034. }
  1035. }
  1036. private bool DebugStart(object data, ref string uuid)
  1037. {
  1038. try
  1039. {
  1040. //System.Collections.IList list = param["list"] as System.Collections.IList;
  1041. //JArray itemObject = (JArray)keyValuePair.Value;
  1042. //foreach (KeyValuePair<string, JToken> keyValuePair in jobject)
  1043. if (data == null) return false;
  1044. if (string.IsNullOrEmpty(data.ToString())) return false;
  1045. JObject jObject = JObject.Parse(data.ToString());
  1046. string tlsn = jObject["tlSn"].ToString();
  1047. uuid = jObject["uuid"].ToString();
  1048. int housesn = int.Parse(jObject["houseSn"].ToString());
  1049. switch (housesn)
  1050. {
  1051. case 1:
  1052. HouseBin1.IsDebug = true;
  1053. break;
  1054. case 2:
  1055. HouseBin2.IsDebug = true;
  1056. break;
  1057. case 3:
  1058. HouseBin3.IsDebug = true;
  1059. break;
  1060. case 4:
  1061. HouseBin4.IsDebug = true;
  1062. break;
  1063. case 5:
  1064. HouseBin5.IsDebug = true;
  1065. break;
  1066. case 6:
  1067. HouseBin6.IsDebug = true;
  1068. break;
  1069. case 7:
  1070. HouseBin7.IsDebug = true;
  1071. break;
  1072. case 8:
  1073. HouseBin8.IsDebug = true;
  1074. break;
  1075. case 9:
  1076. HouseBin9.IsDebug = true;
  1077. break;
  1078. case 10:
  1079. HouseBin10.IsDebug = true;
  1080. break;
  1081. }
  1082. bool IsDebugOk = false;
  1083. do
  1084. {
  1085. switch (housesn)
  1086. {
  1087. case 1:
  1088. IsDebugOk = HouseBin1.isDebugOk;
  1089. break;
  1090. case 2:
  1091. IsDebugOk = HouseBin2.isDebugOk;
  1092. break;
  1093. case 3:
  1094. IsDebugOk = HouseBin3.isDebugOk;
  1095. break;
  1096. case 4:
  1097. IsDebugOk = HouseBin4.isDebugOk;
  1098. break;
  1099. case 5:
  1100. IsDebugOk = HouseBin5.isDebugOk;
  1101. break;
  1102. case 6:
  1103. IsDebugOk = HouseBin6.isDebugOk;
  1104. break;
  1105. case 7:
  1106. IsDebugOk = HouseBin7.isDebugOk;
  1107. break;
  1108. case 8:
  1109. IsDebugOk = HouseBin8.isDebugOk;
  1110. break;
  1111. case 9:
  1112. IsDebugOk = HouseBin9.isDebugOk;
  1113. break;
  1114. case 10:
  1115. IsDebugOk = HouseBin10.isDebugOk;
  1116. break;
  1117. }
  1118. if (IsDebugOk)
  1119. {
  1120. break;
  1121. }
  1122. Thread.Sleep(1000);
  1123. } while (true);
  1124. return true;
  1125. }
  1126. catch (Exception ex)
  1127. {
  1128. LogService.ExceptionLog(ex, "mqtt.DebugStart", null, LogEnum.RunException);
  1129. return false;
  1130. }
  1131. }
  1132. private bool EmbryoState(object data)
  1133. {
  1134. try
  1135. {
  1136. Embryo embryo = JsonConvert.DeserializeObject<Embryo>(data.ToString());
  1137. DBService.ChangeEmbryoState(embryo);
  1138. HouseBin currentHouseBin = HouseSnToHouseBin(embryo.houseSn);
  1139. if (currentHouseBin == null) return false;
  1140. currentHouseBin.ChangeEmbryoState(embryo);
  1141. return true;
  1142. }
  1143. catch (Exception ex)
  1144. {
  1145. ExLog(ex, "EmbryoState");
  1146. return false;
  1147. }
  1148. }
  1149. private bool UpDataSettingMqtt(object data)
  1150. {
  1151. try
  1152. {
  1153. if (data == null) return false;
  1154. string dataString = data.ToString();
  1155. if (string.IsNullOrEmpty(dataString)) return false;
  1156. JObject jObject = JObject.Parse(dataString);
  1157. string tlsn = jObject["tlSn"].ToString();
  1158. string dateTime = jObject["updateTime"].ToString();
  1159. return UpdateSetting(tlsn);
  1160. }
  1161. catch (Exception ex)
  1162. {
  1163. ExLog(ex, "UpDataSettingMqtt");
  1164. return false;
  1165. }
  1166. }
  1167. public bool HouseAutoFocus(object data)
  1168. {
  1169. try
  1170. {
  1171. HouseAutoFocusMqtt houseAutoFocus = JsonConvert.DeserializeObject<HouseAutoFocusMqtt>(data.ToString());
  1172. if (houseAutoFocus == null || !houseAutoFocus.houseSnList.Any())
  1173. {
  1174. LogService.TLLog($"json转换失败,不更新配置信息{data.ToString()}", LogEnum.RunError);
  1175. return false;
  1176. }
  1177. if (!UpdateSetting(houseAutoFocus.tlSn))
  1178. {
  1179. LogService.TLLog($"更新配置信息失败,不开启自动对焦", LogEnum.RunError);
  1180. return false;
  1181. }
  1182. foreach (var houseSn in houseAutoFocus.houseSnList)
  1183. {
  1184. HouseBin currentHouseBin = HouseSnToHouseBin(houseSn);
  1185. if (currentHouseBin == null)
  1186. {
  1187. LogService.TLLog($"开启自动对焦时,获取舱室为空,{houseSn}、{data.ToString()}", LogEnum.RunError);
  1188. continue;
  1189. }
  1190. currentHouseBin.HouseAutoFocus();
  1191. }
  1192. return true;
  1193. }
  1194. catch (Exception ex)
  1195. {
  1196. ExLog(ex, "HouseAutoFocus");
  1197. return false;
  1198. }
  1199. }
  1200. public bool WellAutoFocus(object data)
  1201. {
  1202. try
  1203. {
  1204. WellAutoFocusMqtt wellAutoFocusMqtt = JsonConvert.DeserializeObject<WellAutoFocusMqtt>(data.ToString());
  1205. if (wellAutoFocusMqtt == null || !wellAutoFocusMqtt.houseSnList.Any()) return false;
  1206. if (!UpdateSetting(wellAutoFocusMqtt.tlSn))
  1207. {
  1208. LogService.TLLog($"更新配置信息失败,不开启自动对焦", LogEnum.RunError);
  1209. return false;
  1210. }
  1211. foreach (var houseSn in wellAutoFocusMqtt.houseSnList)
  1212. {
  1213. HouseBin currentHouseBin = HouseSnToHouseBin(houseSn.house);
  1214. if (currentHouseBin == null) continue;
  1215. currentHouseBin.WellAutoFocus(houseSn.well);
  1216. }
  1217. return true;
  1218. }
  1219. catch (Exception ex)
  1220. {
  1221. ExLog(ex, "WellAutoFocus");
  1222. return false;
  1223. }
  1224. }
  1225. public bool UpdateSetting(string tlsn)
  1226. {
  1227. try
  1228. {
  1229. var initTLResult = SerialBinController.UpdataSettingController(tlsn);
  1230. if (initTLResult == null)
  1231. {
  1232. LogService.TLLog($"更新设置时返回为空", LogEnum.RunError);
  1233. return false;
  1234. }
  1235. TLSetting = initTLResult.TLSetting;
  1236. PathHelper.pan = initTLResult.TLSetting.tmpDir;
  1237. LogService.Pan = initTLResult.TLSetting.tmpDir;
  1238. for (int i = 1; i <= 10; i++)
  1239. {
  1240. HouseBin currentHouseBin = HouseSnToHouseBin(i);
  1241. if (currentHouseBin == null) continue;
  1242. currentHouseBin.UpdataHouseSetting(initTLResult);
  1243. }
  1244. //UpdataKafkaAndMqtt();
  1245. return true;
  1246. }
  1247. catch (Exception ex)
  1248. {
  1249. ExLog(ex, "UpdateSetting");
  1250. return false;
  1251. }
  1252. }
  1253. #endregion
  1254. /// <summary>
  1255. /// mqtt报警
  1256. /// </summary>
  1257. /// <param name="message"></param>
  1258. public void MqttAlarm(string message)
  1259. {
  1260. try
  1261. {
  1262. HttpService.AlarmApi1(TLSetting.tlSn, "CLOUD_SLAVE_MQTT_ALARM", new List<string> { message });
  1263. }
  1264. catch (Exception ex)
  1265. {
  1266. ExLog(ex, "mqtt报警");
  1267. return;
  1268. }
  1269. }
  1270. /// <summary>
  1271. /// 上报启动期坏舱告警(每坏舱一条),复用现有 reportAlarm 报警闭环:
  1272. /// SerialBinController.ReportAlarmController → /reportAlarm → 报警责任链 → alarm 表
  1273. /// → front/operate 报警列表 + 短信/电话通知 + 可静音/恢复自动消警(与运行期 HouseStateEvent 同一入口)。
  1274. /// 维度码 0正常/1异常/-1跳过:相机类故障 → photoState=1;串口/编号/Init 类 → comState=1;其余维度 -1(不误清别的告警)。
  1275. /// 全 try 兜底,失败不影响启动。不走 reportCloudAlarm(群消息),无新增 alarmTypeKey、无 Java 改动。
  1276. /// </summary>
  1277. public void ReportStartupFaults()
  1278. {
  1279. if (StartupFaults == null || StartupFaults.Count == 0) return;
  1280. string tlSn = "";
  1281. try { tlSn = TLSetting?.tlSn ?? ""; } catch { }
  1282. foreach (var f in StartupFaults)
  1283. {
  1284. // 舱号未知(相机/串口级)定位不到具体舱,不进 reportAlarm(仍在 /status Faults 里可见)。
  1285. if (f.HouseSn <= 0) continue;
  1286. try
  1287. {
  1288. bool cameraFault = f.Type == HouseFaultType.CcdSnMissing
  1289. || f.Type == HouseFaultType.CcdSnDuplicate
  1290. || f.Type == HouseFaultType.CameraDuplicateSn
  1291. || f.Type == HouseFaultType.CameraReadFailed;
  1292. int comState = cameraFault ? -1 : 1; // 串口/编号/Init 异常
  1293. int photoState = cameraFault ? 1 : -1; // 相机异常
  1294. SerialBinController.ReportAlarmController(tlSn, f.HouseSn, -1, comState, photoState, -1, -1);
  1295. }
  1296. catch (Exception ex) { ExLog(ex, "ReportStartupFaults"); }
  1297. }
  1298. }
  1299. public void KafkaAlarm(string tlsn, int housesn, ulong dishId, ulong embryoId, string imageName, int wellSn)
  1300. {
  1301. try
  1302. {
  1303. HttpService.AlarmApi(tlsn, housesn, wellSn, "CLOUD_SLAVE_KAFKA_ALARM", new List<string> { dishId.ToString(), embryoId.ToString(), imageName });
  1304. }
  1305. catch (Exception ex)
  1306. {
  1307. ExLog(ex, "图片传输失败报警");
  1308. return;
  1309. }
  1310. }
  1311. public void KafkaAlarmChaoShi(string tlsn, int housesn, ulong dishId, ulong embryoId, string imageName, int wellSn)
  1312. {
  1313. try
  1314. {
  1315. HttpService.AlarmApi(tlsn, housesn, wellSn, "CLOUD_SLAVE_PICTURE_TRANSFER_ALARM", new List<string> { dishId.ToString(), embryoId.ToString(), imageName });
  1316. }
  1317. catch (Exception ex)
  1318. {
  1319. ExLog(ex, "图片传输超时报警");
  1320. return;
  1321. }
  1322. }
  1323. private async Task KafkaUploadImageAsync(string fileFullPath)
  1324. {
  1325. // M5-04-3(a):去重防并发重传。同名文件在上一轮上传未结束(慢链/超时)时,5s 重扫会再次进入本方法,
  1326. // 此处用 in-flight 集合保证同一文件同一时刻只有一条上传在跑;释放放在 finally,不影响「成功才删」语义。
  1327. string fileName = Path.GetFileName(fileFullPath);
  1328. lock (_uploadingFiles)
  1329. {
  1330. if (_uploadingFiles.Contains(fileName)) return; // 正在上传,跳过本轮重扫的重复触发
  1331. _uploadingFiles.Add(fileName);
  1332. }
  1333. try
  1334. {
  1335. Stopwatch stopwatch = Stopwatch.StartNew();
  1336. //LogService.TLLog($"准备上传{fileFullPath}", LogEnum.KafkaRecord);
  1337. ImageDTO imageDTO = null;
  1338. lock (ImageDTODic) if (ImageDTODic.ContainsKey(fileName)) imageDTO = ImageDTODic[fileName];
  1339. if (imageDTO == null)
  1340. {
  1341. imageDTO = SerialBinController.SearchPictureController(fileName, TLSetting.tlSn);
  1342. if (imageDTO == null)
  1343. {
  1344. LogService.TLLog($"数据库获取文件失败:{fileName}、{TLSetting.tlSn}:{fileFullPath}", LogEnum.RunError);
  1345. }
  1346. else
  1347. {
  1348. var imageBytes = AivfoHelper.GetImageData1(fileFullPath);
  1349. if (imageBytes == null)
  1350. {
  1351. LogService.TLLog($"上传中止,图片不存在:{fileFullPath}", LogEnum.RunError);
  1352. }
  1353. else
  1354. {
  1355. imageDTO.ImageData = ByteString.CopyFrom(imageBytes);
  1356. }
  1357. }
  1358. }
  1359. if (imageDTO == null)
  1360. {
  1361. LogService.TLLog($"上传中止,imageDTO为空:{fileFullPath}", LogEnum.KafkaRecord);
  1362. string newDir = PathHelper.GetErrorSaveDirectory();
  1363. if (!Directory.Exists(newDir)) Directory.CreateDirectory(newDir);
  1364. File.Move(fileFullPath, Path.Combine(newDir, fileName));
  1365. return;
  1366. }
  1367. //LogService.TLLog($"fileName文件大小:{imageDTO.ImageData.Count()}", LogEnum.KafkaRecord);
  1368. var time1 = stopwatch.Elapsed;
  1369. //LogService.TLLog($"开始上传{fileFullPath},准备耗时:{time1}毫秒", LogEnum.KafkaRecord);
  1370. var uploadResult = await KafkaService.kafkaProducerAsync(imageDTO);
  1371. var time2 = stopwatch.Elapsed;
  1372. //LogService.TLLog($"上传结束{fileFullPath},耗时:{time2 - time1}毫秒", LogEnum.KafkaRecord);
  1373. if (!uploadResult)
  1374. {
  1375. KafkaAlarm(imageDTO.TlSn, imageDTO.HouseSn, imageDTO.EmbryoCultureRecordId, imageDTO.EmbryoId, imageDTO.SourceImageName, imageDTO.WellSn);
  1376. LogService.TLLog($"上传失败:{fileFullPath}", LogEnum.RunError);
  1377. return;
  1378. }
  1379. if ((time2 - time1).TotalMilliseconds > 1000)
  1380. {
  1381. KafkaAlarmChaoShi(imageDTO.TlSn, imageDTO.HouseSn, imageDTO.EmbryoCultureRecordId, imageDTO.EmbryoId, imageDTO.SourceImageName, imageDTO.WellSn);
  1382. LogService.TLLog($"kafka上传超时:{fileFullPath}", LogEnum.RunError);
  1383. }
  1384. LastKafkaOkAt = DateTime.Now; // M5-03-2:Kafka 图片上传成功时间戳(只读监控用,不改上传逻辑)
  1385. lock (ImageDTODic) if (ImageDTODic.ContainsKey(fileName)) ImageDTODic.Remove(fileName);
  1386. if (File.Exists(fileFullPath))
  1387. {
  1388. try
  1389. {
  1390. File.Delete(fileFullPath);
  1391. }
  1392. catch (Exception ex)
  1393. {
  1394. LogService.ExceptionLog(ex, "kafka上传完成删除图片", null, LogEnum.RunException);
  1395. }
  1396. //if (imageDTO.PhotographType == 1)
  1397. //{
  1398. // string newpath = @"C:\TLData\AutofocusControlBreak";
  1399. // if (!Directory.Exists(newpath)) Directory.CreateDirectory(newpath);
  1400. // File.Move(fileFullPath, Path.Combine(newpath, fileName));
  1401. //}
  1402. //else
  1403. //{
  1404. // string newpath = @"C:\TLData\EmbryosControlBreak";
  1405. // if (!Directory.Exists(newpath)) Directory.CreateDirectory(newpath);
  1406. // File.Move(fileFullPath, Path.Combine(newpath, fileName));
  1407. //}
  1408. }
  1409. SerialBinController.DeletePictrueController(fileName, TLSetting.tlSn);
  1410. //LogService.TLLog($"上传完成:{fileFullPath},总耗时:{stopwatch.ElapsedMilliseconds}毫秒", LogEnum.KafkaRecord);
  1411. }
  1412. catch (Exception ex)
  1413. {
  1414. LogService.ExceptionLog(ex, "kafka上传图片", null, LogEnum.RunException);
  1415. return;
  1416. }
  1417. finally
  1418. {
  1419. // M5-04-3(a):无论成功/失败/中止,都释放 in-flight 标记,使下一轮重扫可重试(失败文件仍在落盘 → 不丢)。
  1420. lock (_uploadingFiles) _uploadingFiles.Remove(fileName);
  1421. }
  1422. }
  1423. private HouseMqttData GetHouseMqttData(HouseBin currentHouseBin)
  1424. {
  1425. if (currentHouseBin == null) return null;
  1426. if (currentHouseBin.House == null) return null;
  1427. int cultureState = 0;
  1428. if (currentHouseBin.Balance != null && currentHouseBin.Balance.id > 0) cultureState = 2;
  1429. if (currentHouseBin.Dish != null && currentHouseBin.Dish.id > 0) cultureState = 1;
  1430. return new HouseMqttData()
  1431. {
  1432. tlSn = TLSetting.tlSn,
  1433. houseSn = currentHouseBin.House.houseSn,
  1434. pressure = currentHouseBin.Pressure,
  1435. temperature = currentHouseBin.Temperature,
  1436. houseDoorState = currentHouseBin.IsDoorOpen == State.打开 ? 1 : 0,
  1437. pressureDesc = currentHouseBin.ValveState.ToString(),
  1438. houseDesc = currentHouseBin.RunState,
  1439. cultureState = cultureState,
  1440. houseState = (int)currentHouseBin.WorkingType,
  1441. };
  1442. }
  1443. private HouseMqttData GetHouseMqttData(BufferBottleBin currentBufferBottleBin)
  1444. {
  1445. if (currentBufferBottleBin == null) return null;
  1446. if (currentBufferBottleBin.House == null) return null;
  1447. return new HouseMqttData()
  1448. {
  1449. tlSn = TLSetting.tlSn,
  1450. houseSn = 11,
  1451. pressure = currentBufferBottleBin.BufferBottlePressure,
  1452. temperature = 0,
  1453. houseDoorState = 0,
  1454. pressureDesc = currentBufferBottleBin.ValveState.ToString(),
  1455. houseDesc = currentBufferBottleBin.RunState,
  1456. };
  1457. }
  1458. private HouseHistoryData GetHouseHistoryData(HouseBin currentHouseBin)
  1459. {
  1460. if (currentHouseBin == null) return null;
  1461. if (currentHouseBin.House == null) return null;
  1462. return new HouseHistoryData()
  1463. {
  1464. tlSn = TLSetting.tlSn,
  1465. houseSn = currentHouseBin.House.houseSn,
  1466. pressure = currentHouseBin.Pressure,
  1467. temperature = currentHouseBin.Temperature,
  1468. houseDoor = currentHouseBin.IsDoorOpen == State.打开 ? 1 : 0,
  1469. airSwap = currentHouseBin.WorkingType == WorkingType.AirSwapWorking ? 1 : 0,
  1470. temperatureLowerCover = currentHouseBin.Temperature2,
  1471. temperatureUpperCover = currentHouseBin.Temperature1,
  1472. temperatureLowerGlass = currentHouseBin.Temperature3,
  1473. };
  1474. }
  1475. private HouseHistoryData GetHouseHistoryData(BufferBottleBin currentBufferBottleBin)
  1476. {
  1477. if (currentBufferBottleBin == null) return null;
  1478. if (currentBufferBottleBin.House == null) return null;
  1479. return new HouseHistoryData()
  1480. {
  1481. tlSn = TLSetting.tlSn,
  1482. houseSn = 11,
  1483. pressure = currentBufferBottleBin.BufferBottlePressure,
  1484. temperature = 0,
  1485. houseDoor = 0,
  1486. airSwap = 0,
  1487. temperatureLowerCover = currentBufferBottleBin.Temperature1,
  1488. temperatureUpperCover = currentBufferBottleBin.Temperature2,
  1489. temperatureLowerGlass = 0,
  1490. cultureState = 0,
  1491. };
  1492. }
  1493. private HouseBin HouseSnToHouseBin(int housesn)
  1494. {
  1495. HouseBin result = null;
  1496. switch (housesn)
  1497. {
  1498. case 1:
  1499. result = HouseBin1;
  1500. break;
  1501. case 2:
  1502. result = HouseBin2;
  1503. break;
  1504. case 3:
  1505. result = HouseBin3;
  1506. break;
  1507. case 4:
  1508. result = HouseBin4;
  1509. break;
  1510. case 5:
  1511. result = HouseBin5;
  1512. break;
  1513. case 6:
  1514. result = HouseBin6;
  1515. break;
  1516. case 7:
  1517. result = HouseBin7;
  1518. break;
  1519. case 8:
  1520. result = HouseBin8;
  1521. break;
  1522. case 9:
  1523. result = HouseBin9;
  1524. break;
  1525. case 10:
  1526. result = HouseBin10;
  1527. break;
  1528. }
  1529. return result;
  1530. }
  1531. public DiskInfo GetDiskInfo(string pan)
  1532. {
  1533. DiskInfo diskInfo = new DiskInfo() { diskPath = pan };
  1534. try
  1535. {
  1536. string panNew = pan.ToUpper();
  1537. diskInfo.diskExist = Directory.Exists($"{panNew}:\\") ? 0 : 1;
  1538. if (diskInfo.diskExist == 1) return diskInfo;
  1539. bool IsFind = false;
  1540. DriveInfo[] allDirves = DriveInfo.GetDrives();
  1541. foreach (DriveInfo item in allDirves)
  1542. {
  1543. if (item.IsReady)
  1544. {
  1545. if (item.Name == $"{panNew}:\\")
  1546. {
  1547. IsFind = true;
  1548. diskInfo.diskSpace = (decimal)(item.TotalFreeSpace / (1024.00 * 1024.00 * 1024.00));
  1549. break;
  1550. }
  1551. }
  1552. }
  1553. if (!IsFind) diskInfo.diskExist = 1;
  1554. return diskInfo;
  1555. }
  1556. catch (Exception ex)
  1557. {
  1558. LogService.ExceptionLog(ex, "GetDiskInfo", null, LogEnum.RunException);
  1559. diskInfo.diskExist = 1;
  1560. return diskInfo;
  1561. }
  1562. }
  1563. public void DeleteLog()
  1564. {
  1565. try
  1566. {
  1567. string newPath = $"{TLSetting.tmpDir}:\\TLData\\ivf_tl_Control_logs";
  1568. var newDir = Directory.GetDirectories(newPath, "*", SearchOption.TopDirectoryOnly);
  1569. foreach (var item in newDir)
  1570. {
  1571. var dieName = System.IO.Path.GetFileName(item);
  1572. if (DateTime.TryParse(dieName, out DateTime newTime))
  1573. {
  1574. if (DateTime.Now.Subtract(newTime).Days >= 5)
  1575. {
  1576. Directory.Delete(item, true);
  1577. }
  1578. }
  1579. }
  1580. DeleteLogFile($"C:\\TLData\\ivf_tl_Control_logs\\LogError");
  1581. DeleteLogFile($"C:\\TLData\\ivf_tl_Control_logs\\Log");
  1582. }
  1583. catch (Exception ex)
  1584. {
  1585. LogService.ExceptionLog(ex, "DeleteLog", null, LogEnum.RunException);
  1586. }
  1587. }
  1588. /// <summary>
  1589. /// G4-1 / 需求文档12 §2.7:对焦标定数据清理(每日维护窗口触发,与 DeleteLog 同源)。
  1590. /// 保留天数取服务器下发的 TLSetting.cleanAutofocusData(缺省/非正回退 30);
  1591. /// 只删 scene=1 日常对焦记录、scene=0 出厂基准永久保留(由 DBService.CleanAutofocusData 保证)。
  1592. /// 全 try 兜底,异常吞掉记日志,绝不向上抛(不影响采集/对焦)。
  1593. /// </summary>
  1594. public void CleanAutofocusCalibration()
  1595. {
  1596. try
  1597. {
  1598. int keepDays = TLSetting?.cleanAutofocusData ?? 30;
  1599. if (keepDays <= 0) keepDays = 30;
  1600. int n = DBService.CleanAutofocusData(keepDays);
  1601. LogService.TLLog($"对焦标定清理(G4-1):保留 {keepDays} 天,删除 scene=1 共 {n} 条", LogEnum.RunRecord);
  1602. }
  1603. catch (Exception ex)
  1604. {
  1605. LogService.ExceptionLog(ex, "CleanAutofocusCalibration", null, LogEnum.RunException);
  1606. }
  1607. }
  1608. private void DeleteLogFile(string newPath)
  1609. {
  1610. var newDir = Directory.GetFiles(newPath, "*.htm", SearchOption.TopDirectoryOnly);
  1611. string fileName = "";
  1612. DateTime fileTime = DateTime.Now;
  1613. DateTime nowTime = fileTime;
  1614. foreach (var item in newDir)
  1615. {
  1616. fileName = System.IO.Path.GetFileNameWithoutExtension(item);
  1617. if (fileName.Length == 8)
  1618. {
  1619. fileName = fileName.Insert(6, "-");
  1620. fileName = fileName.Insert(4, "-");
  1621. if (DateTime.TryParse(fileName, out fileTime))
  1622. {
  1623. if (nowTime.Subtract(fileTime).Days >= 5)
  1624. {
  1625. try
  1626. {
  1627. File.Delete(item);
  1628. }
  1629. catch (Exception)
  1630. {
  1631. continue;
  1632. }
  1633. }
  1634. }
  1635. }
  1636. }
  1637. }
  1638. public string ReadText(string fileName)
  1639. {
  1640. return File.ReadAllText(fileName);
  1641. }
  1642. public PositionInfoResultDTO HouseBin_GetCCDServiceEventTest(int arg1, Dictionary<int, DateTime?> arg3)
  1643. {
  1644. List<WellSnAndAutoTime> wellSnAndAutoTimes = new List<WellSnAndAutoTime>();
  1645. foreach (var item in arg3)
  1646. {
  1647. wellSnAndAutoTimes.Add(new WellSnAndAutoTime
  1648. {
  1649. well = item.Key,
  1650. autofocusTime = item.Value.HasValue ? item.Value.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
  1651. });
  1652. }
  1653. PositionRequestDTO positionRequestDTO = new PositionRequestDTO()
  1654. {
  1655. houseSn = arg1,
  1656. wellSnList = wellSnAndAutoTimes,
  1657. tlSn = "NEO-1-20230410",
  1658. };
  1659. var result = HouseBinController.GetCCDPositionController(positionRequestDTO);
  1660. if (result != null && result.complete == 0)//完成
  1661. {
  1662. List<HouseWellPhoto> CCDPositionList = new List<HouseWellPhoto>();
  1663. foreach (var item in result.positionVOList)
  1664. {
  1665. CCDPositionList.Add(ConvertHelper.ConvertToHouseWellPhoto(item));
  1666. }
  1667. HouseBinController.DbUpdatePositionData(CCDPositionList, positionRequestDTO.houseSn, positionRequestDTO.tlSn, 1);
  1668. }
  1669. return result;
  1670. }
  1671. public List<HouseWellPhoto> HouseBin_GetAutoFocusServiceEventTest(int arg1, Dictionary<int, DateTime?> arg3)
  1672. {
  1673. List<WellSnAndAutoTime> wellSnAndAutoTimes = new List<WellSnAndAutoTime>();
  1674. foreach (var item in arg3)
  1675. {
  1676. wellSnAndAutoTimes.Add(new WellSnAndAutoTime
  1677. {
  1678. well = item.Key,
  1679. autofocusTime = item.Value.HasValue ? item.Value.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
  1680. });
  1681. }
  1682. PositionRequestDTO positionRequestDTO = new PositionRequestDTO()
  1683. {
  1684. houseSn = arg1,
  1685. tlSn = "NEO-1-20230410",
  1686. wellSnList = wellSnAndAutoTimes,
  1687. };
  1688. return HouseBinController.GetAutoFocusController(positionRequestDTO);
  1689. }
  1690. public string GetLanguageStringByKey(string key)
  1691. {
  1692. try
  1693. {
  1694. if (System.Windows.Application.Current == null) return "";
  1695. object value = System.Windows.Application.Current.TryFindResource(key);
  1696. return value == null ? "" : value.ToString();
  1697. }
  1698. catch (Exception)
  1699. {
  1700. return "";
  1701. }
  1702. }
  1703. }
  1704. }