qxz_zhijian_new.py 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498
  1. # -*- coding: utf-8 -*-
  2. # Form implementation generated from reading ui file '.\ui文件\气象站质检工具.ui'
  3. #
  4. # Created by: PyQt5 UI code generator 5.15.4
  5. #
  6. # WARNING: Any manual changes made to this file will be lost when pyuic5 is
  7. # run again. Do not edit this file unless you know what you are doing.
  8. # pyinstaller -n "气象站(v3.2)" -D -w f:\image_down_code\qxz_zhijian.py -i .\LOGO.ico
  9. from cgi import print_arguments
  10. from multiprocessing.managers import DictProxy
  11. from operator import delitem
  12. from unittest import result
  13. from PyQt5 import QtCore, QtGui, QtWidgets
  14. import os
  15. import sys
  16. import re
  17. import ast
  18. from urllib import parse
  19. import json
  20. import time
  21. import datetime
  22. import requests
  23. import uuid
  24. import pymongo
  25. import pymysql
  26. from collections import defaultdict, Counter
  27. from xlrd import open_workbook
  28. from xlsxwriter.workbook import Workbook
  29. import openpyxl
  30. save_filename = ""
  31. pwd_str = "yf6021"
  32. toji_format = {
  33. 'font_name' : '宋体',
  34. 'font_size': 14,
  35. 'font_color': 'black',
  36. 'text_wrap': True,
  37. 'bold': False,
  38. 'fg_color': '92D050',
  39. 'align': 'center',
  40. 'valign': 'vcenter',
  41. 'border': 1,
  42. 'top': 1,
  43. 'left': 1,
  44. 'right': 1,
  45. 'bottom': 1
  46. }
  47. title_format = {
  48. 'font_name' : '宋体',
  49. 'font_size': 12,
  50. 'bold': True,
  51. 'align': 'center',
  52. 'valign': 'vcenter',
  53. 'border': 1,
  54. 'top': 1,
  55. 'left': 1,
  56. 'right': 1,
  57. 'bottom': 1
  58. }
  59. merge_title_format = {
  60. 'font_name' : '宋体',
  61. 'font_size': 26,
  62. 'bold': True,
  63. 'align': 'center',
  64. 'valign': 'vcenter',
  65. "fg_color": "8DB4E2",
  66. 'border': 1,
  67. 'top': 1,
  68. 'left': 1,
  69. 'right': 1,
  70. 'bottom': 1
  71. }
  72. explain_formal = {
  73. 'font_name' : '宋体',
  74. 'font_size': 11,
  75. 'font_color': 'black',
  76. 'text_wrap': True,
  77. 'align': 'justify',
  78. 'valign': 'vcenter',
  79. 'border': 1,
  80. 'top': 1,
  81. 'left': 1,
  82. 'right': 1,
  83. 'bottom': 1
  84. }
  85. formal_format = {
  86. 'font_name' : '宋体',
  87. 'font_size': 11,
  88. 'font_color': 'black',
  89. 'fg_color': '77E88C',
  90. 'text_wrap': True,
  91. 'align': 'center',
  92. 'valign': 'vcenter',
  93. 'border': 1,
  94. 'top': 1,
  95. 'left': 1,
  96. 'right': 1,
  97. 'bottom': 1
  98. }
  99. common_format = {
  100. 'font_name' : '宋体',
  101. 'font_size': 11,
  102. 'font_color': 'black',
  103. "fg_color": 'E7EC73',
  104. 'text_wrap': True,
  105. 'align': 'center',
  106. 'valign': 'vcenter',
  107. 'border': 1,
  108. 'top': 1,
  109. 'left': 1,
  110. 'right': 1,
  111. 'bottom': 1
  112. }
  113. error_format = {
  114. 'font_name' : '宋体',
  115. 'font_size': 11,
  116. 'font_color': 'black',
  117. "fg_color": 'F4746A',
  118. 'text_wrap': True,
  119. 'align': 'center',
  120. 'valign': 'vcenter',
  121. 'border': 1,
  122. 'top': 1,
  123. 'left': 1,
  124. 'right': 1,
  125. 'bottom': 1
  126. }
  127. default_formal = {
  128. 'font_name': '宋体',
  129. 'font_size': 11,
  130. 'font_color': 'black',
  131. 'text_wrap': True,
  132. 'align': 'center',
  133. 'valign': 'vcenter',
  134. 'border': 1,
  135. 'top': 1,
  136. 'left': 1,
  137. 'right': 1,
  138. 'bottom': 1
  139. }
  140. class QxzCand:
  141. def __init__(self):
  142. self.func_dict = {
  143. "空气温度": self.get_cond_101,
  144. "空气湿度": self.get_cond_102,
  145. "土壤温度": self.get_cond_106,
  146. "土壤含水率": self.get_cond_107,
  147. "风速": self.get_cond_108,
  148. "风向": self.get_cond_109,
  149. "降雨量累计": self.get_cond_115,
  150. "光合有效辐射": self.get_cond_123,
  151. "气压": self.get_cond_127,
  152. "盐分": self.get_cond_154,
  153. "电导率": self.get_cond_211,
  154. "磷": self.get_cond_156,
  155. "日照时数": self.get_cond_113,
  156. "PM2.5": self.get_cond_145,
  157. "PM10": self.get_cond_146,
  158. "总辐射": self.get_cond_105,
  159. "负氧离子": self.get_cond_162,
  160. "二氧化碳": self.get_cond_120,
  161. "蒸发量": self.get_cond_110,
  162. "土壤PH": self.get_cond_128,
  163. "紫外辐射": self.get_cond_138,
  164. "水质pH": self.get_cond_228,
  165. "水位": self.get_cond_230,
  166. "水质电导率": self.get_cond_178,
  167. "光照度": self.get_cond_112,
  168. "硫化氢": self.get_cond_219,
  169. "水温": self.get_cond_144,
  170. "浊度": self.get_cond_151,
  171. "氨气": self.get_cond_153,
  172. "氧气": self.get_cond_220,
  173. "PM100": self.get_cond_203,
  174. "露点温度": self.get_cond_202,
  175. "氮": self.get_cond_155,
  176. "钾": self.get_cond_157,
  177. "溶解氧": self.get_cond_148,
  178. }
  179. self.cond_msg_dict = {}
  180. for k, v in self.func_dict.items():
  181. self.cond_msg_dict[k] = self.get_cond_msg
  182. self.head_dict = {
  183. "ID": "/",
  184. "检验项目": "判定标准",
  185. "经度": "合格条件(绿色):\n113°46′13″±30″范围内",
  186. "纬度": "合格条件(绿色):\n35°1′45″±30″范围内",
  187. "固件版本号": "合格条件(绿色):\n用检验时的输入作为导入的标准.\n/ 无法显示,替换为 -",
  188. "电压": "合格条件(绿色):\n11~15",
  189. "信号强度": "合格条件(绿色):\n>14",
  190. "上传数据条数": "合格条件(绿色):\n1、大于7条\n2、两条数据时间间隔小于20分钟的出现频次2次以内、两条数据间隔大于40分钟出现频率2次以内",
  191. "风速": "合格条件(绿色):\n1、0<示值<10\n2、有1条合格 即可",
  192. "风向": "合格条件(绿色):\n1、0<示值<360\n2、有1条合格即可",
  193. "降雨量累计": "合格条件(绿色):\n1、0<示值\n2、00:00示值归零\n3、有1条合格即可",
  194. "土壤含水率": "合格条件(绿色):\n1、0<示值<=100\n2、有1条合格即可",
  195. "土壤温度": "合格条件(绿色):\n1.≠0且在-5~35°C之间\n2、有1条合格即可",
  196. "盐分": "合格条件(绿色):\n1、0<示值<1000#2、有1条合格即可",
  197. "电导率": "合格条件(绿色):\n1、0<示值\n2、有1条合格即",
  198. "氮": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  199. "磷": "合格条件(绿色):\n1、0<示值且不能为负值\n2、有1条合格即可",
  200. "光合有效辐射": "合格条件(绿色):\n1、0<示值且不能为负值\n2、有1条合格即可",
  201. "日照时数": "合格条件(绿色):\n1、0.1≤示值\n2、有1条合格即可",
  202. "PM2.5": "合格条件(绿色):\n1、0<示值且不能为负值\n2、有1条合格即可",
  203. "PM10": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  204. "负氧离子": "合格条件(绿色):\n1、0<示值<1000\n2、有1条合格即可",
  205. "总辐射": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  206. "二氧化碳": "合格条件(绿色):\n1、400<示值<1500\n2、有1条合格即可",
  207. "蒸发量": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  208. "土壤PH": "合格条件(绿色):\n1、6~8\n2、有1条合格即可",
  209. "钾": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  210. "紫外辐射": "合格条件(绿色):\n1、0<示 值\n2、有1条合格即可",
  211. "空气温度": "合格条件(绿色):\n1.-10~35°C,但不允许为0°C\n2、有1条合格即可",
  212. "空气湿度": "合格条件(绿色):\n1、0<示值<100\n2、有1条合格即可",
  213. "水质pH": "合格条件(绿色):\n1、6≤示值≤8\n2、有1条合格即可",
  214. "水位": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  215. "水质电导率": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  216. "气压": "合格条件(绿色):\n1、900<示值<1150\n2、有1条合格即可",
  217. "光照度": "合格条件(绿色):\n1、0<示值<200000\n2、有1条合格即可",
  218. "硫化氢": "合格条件(绿色):\n1、示值=0\n2、有1条合格即可",
  219. "水温": "合格条件(绿色):\n1.0~30°C,但不允许为0°C\n2、 有1条合格即可",
  220. "溶解氧": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  221. "浊度": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  222. "氨气": "合格条件(绿色):\n1、示值=0\n2、有1条合格即可",
  223. "氧气": "合格条件(绿色):\n1、0<示值\n2、有1条合格即可",
  224. "PM100": "合格条件(绿色):\n1、0<示值\n2 、有1条合格即可",
  225. "露点温度": "合格条件(绿色):\n1.-10~35°C,但不允许为0°C\n2、有1条合格即可",
  226. "sim卡信息": "合格条件(绿色):\n1、大于等于180天单元格显示绿色\n2、小于180天大于等于30天单元格显示黄色、\n3、小于30天单元格显示为红色",
  227. "位置信息": "合格条件(绿色):显示河南省新乡市原阳县为合格,否则不合格",
  228. "单台合格数": "合格条件(绿色):\n所有显示数值全部在合格范围内,则判定为合格"
  229. }
  230. def get_cond_lat_msg(self, info):
  231. return {
  232. "status": int(info["status"]),
  233. "msg": f"纬度为: {info['lat']}"
  234. }
  235. def get_cond_lng_msg(self, info):
  236. return {
  237. "status": int(info["status"]),
  238. "msg": f"经度为: {info['lng']}"
  239. }
  240. def get_cond_volt_msg(self, info):
  241. return self.get_cond_msg(info)
  242. def get_cond_rssi_msg(self, info):
  243. return self.get_cond_msg(info)
  244. def get_cond_version_msg(self, info):
  245. status = info["status"]
  246. value = info["dver_num"]
  247. old_value = info["old_value"]
  248. device_version = value.replace('/', '-')
  249. old_version = old_value.replace('/', '-')
  250. return {
  251. "status": status,
  252. "msg": f"设备:{device_version}, 输入:{old_version}"
  253. }
  254. def get_cond_sim_msg(self, info):
  255. return info
  256. def get_time_uptime_msg(self, info):
  257. total_count = int(info["total_count"])
  258. uptime_20 = int(info["uptime_20"])
  259. uptime_40 = int(info["uptime_40"])
  260. msg = f"数据量:{total_count},间隔<20分钟:{uptime_20},间隔>40分钟:{uptime_40}"
  261. status = 0
  262. if total_count > 7 and uptime_20 <= 2 and uptime_40 <= 2:
  263. status = 1
  264. return {
  265. "status": status,
  266. "msg": msg
  267. }
  268. def get_cond_msg(self, info):
  269. """获取输出结果"""
  270. max_value = info['max_value']
  271. min_value = info['min_value']
  272. status = int(info['status'])
  273. msg = f"最大值:{max_value},最小值:{min_value}"
  274. return {"status": status, "msg": msg}
  275. def template_func(self, ek, cond_str):
  276. """获取模板函数"""
  277. cond = {
  278. "$function": {
  279. "args": [f"${ek}"],
  280. "lang": "js",
  281. "body": f"""
  282. function(values_list){{
  283. let max_value = Math.max(...values_list);
  284. let min_value = Math.min(...values_list);
  285. let status = 0;
  286. for (let i = 0; i < values_list.length; i++){{
  287. let v = values_list[i];
  288. if ({cond_str}){{
  289. status = 1;
  290. break;
  291. }}
  292. }}
  293. return {{"max_value": max_value, "min_value": min_value, "status": status}}
  294. }}
  295. """
  296. }
  297. }
  298. return cond
  299. def get_cond_101(self, ek):
  300. """获取空气温度条件"""
  301. cond = self.template_func(ek, "v != 0 && -10 <= v && v <= 35")
  302. return cond
  303. def get_cond_102(self, ek):
  304. """获取空气湿度条件"""
  305. cond = self.template_func(ek, "0 < v && v < 100")
  306. return cond
  307. def get_cond_106(self, ek):
  308. """获取土壤温度条件"""
  309. cond = self.template_func(ek, "v != 0 && -5 <= v && v <= 35")
  310. return cond
  311. def get_cond_107(self, ek):
  312. """获取土壤含水率条件"""
  313. cond = self.template_func(ek, "0 < v && v <= 100")
  314. return cond
  315. def get_cond_108(self, ek):
  316. """获取风速条件"""
  317. cond = self.template_func(ek, "0 < v && v < 10")
  318. return cond
  319. def get_cond_109(self, ek):
  320. """获取风向条件"""
  321. cond = self.template_func(ek, "0 < v && v < 360")
  322. return cond
  323. def get_cond_115(self, ek):
  324. """获取降雨量累计条件"""
  325. cond = self.template_func(ek, "0 < v")
  326. return cond
  327. def get_cond_123(self, ek):
  328. """获取光合有效辐射条件"""
  329. cond = self.template_func(ek, "0 < v")
  330. return cond
  331. def get_cond_127(self, ek):
  332. """获取气压条件"""
  333. cond = self.template_func(ek, "900 < v && v < 1150")
  334. return cond
  335. def get_cond_154(self, ek):
  336. """获取盐分条件"""
  337. cond = self.template_func(ek, "0 < v && v < 1000")
  338. return cond
  339. def get_cond_211(self, ek):
  340. """获取电导率条件"""
  341. cond = self.template_func(ek, "0 < v")
  342. return cond
  343. def get_cond_155(self, ek):
  344. """获取氮条件"""
  345. cond = self.template_func(ek, "0 < v")
  346. return cond
  347. def get_cond_156(self, ek):
  348. """获取磷条件"""
  349. cond = self.template_func(ek, "0 < v")
  350. return cond
  351. def get_cond_113(self, ek):
  352. """获取日照时数条件"""
  353. cond = self.template_func(ek, "0.1 <= v")
  354. return cond
  355. def get_cond_145(self, ek):
  356. """获取PM2.5条件"""
  357. cond = self.template_func(ek, "0 < v")
  358. return cond
  359. def get_cond_146(self, ek):
  360. """获取PM10条件"""
  361. cond = self.template_func(ek, "0 < v")
  362. return cond
  363. def get_cond_105(self, ek):
  364. """获取总辐射条件"""
  365. cond = self.template_func(ek, "0 < v")
  366. return cond
  367. def get_cond_162(self, ek):
  368. """获取负氧离子条件"""
  369. cond = self.template_func(ek, "0 < v && v < 1000")
  370. return cond
  371. def get_cond_120(self, ek):
  372. """获取二氧化碳条件"""
  373. cond = self.template_func(ek, "400 < v && v < 1500")
  374. return cond
  375. def get_cond_110(self, ek):
  376. """获取蒸发量条件"""
  377. cond = self.template_func(ek, "0 < v")
  378. return cond
  379. def get_cond_128(self, ek):
  380. """获取土壤PH条件"""
  381. cond = self.template_func(ek, "6 <= v && v <= 8")
  382. return cond
  383. def get_cond_157(self, ek):
  384. """获取钾条件"""
  385. cond = self.template_func(ek, "0 < v")
  386. return cond
  387. def get_cond_138(self, ek):
  388. """获取紫外辐射条件"""
  389. cond = self.template_func(ek, "0 < v")
  390. return cond
  391. def get_cond_228(self, ek):
  392. """获取水质pH条件"""
  393. cond = self.template_func(ek, "6 <= v && v <= 8")
  394. return cond
  395. def get_cond_230(self, ek):
  396. """获取水位条件"""
  397. cond = self.template_func(ek, "0 < v")
  398. return cond
  399. def get_cond_178(self, ek):
  400. """获取水质电导率条件"""
  401. cond = self.template_func(ek, "0 < v")
  402. return cond
  403. def get_cond_112(self, ek):
  404. """获取光照度条件"""
  405. cond = self.template_func(ek, "0 < v && v < 200000")
  406. return cond
  407. def get_cond_219(self, ek):
  408. """获取硫化氢条件"""
  409. cond = self.template_func(ek, "v == 0")
  410. return cond
  411. def get_cond_144(self, ek):
  412. """获取水温条件"""
  413. cond = self.template_func(ek, "0 < v && v <= 30")
  414. return cond
  415. def get_cond_148(self, ek):
  416. """获取溶解氧条件"""
  417. cond = self.template_func(ek, "0 < v")
  418. return cond
  419. def get_cond_151(self, ek):
  420. """获取浊度条件"""
  421. cond = self.template_func(ek, "0 < v")
  422. return cond
  423. def get_cond_153(self, ek):
  424. """获取氨气条件"""
  425. cond = self.template_func(ek, "v == 0")
  426. return cond
  427. def get_cond_220(self, ek):
  428. """获取氧气条件"""
  429. cond = self.template_func(ek, "0 < v")
  430. return cond
  431. def get_cond_203(self, ek):
  432. """获取PM100条件"""
  433. cond = self.template_func(ek, "0 < v")
  434. return cond
  435. def get_cond_202(self, ek):
  436. """获取露点温度条件"""
  437. cond = self.template_func(ek, "-10 < v && v < 35")
  438. return cond
  439. class Ui_MainWindow(object):
  440. """GUI界面"""
  441. def setupUi(self, MainWindow):
  442. MainWindow.setObjectName("MainWindow")
  443. MainWindow.resize(701, 644)
  444. font = QtGui.QFont()
  445. font.setFamily("Arial")
  446. font.setPointSize(12)
  447. MainWindow.setFont(font)
  448. icon = QtGui.QIcon("logo.ico")
  449. MainWindow.setWindowIcon(icon)
  450. self.centralwidget = QtWidgets.QWidget(MainWindow)
  451. self.centralwidget.setObjectName("centralwidget")
  452. self.pageTitleLabel = QtWidgets.QLabel(self.centralwidget)
  453. self.pageTitleLabel.setGeometry(QtCore.QRect(139, 50, 429, 42))
  454. font = QtGui.QFont()
  455. font.setFamily("楷体")
  456. font.setPointSize(28)
  457. self.pageTitleLabel.setFont(font)
  458. self.pageTitleLabel.setTextFormat(QtCore.Qt.AutoText)
  459. self.pageTitleLabel.setObjectName("pageTitleLabel")
  460. self.inputFileLabel = QtWidgets.QLabel(self.centralwidget)
  461. self.inputFileLabel.setGeometry(QtCore.QRect(180, 130, 121, 21))
  462. self.inputFileLabel.setObjectName("inputFileLabel")
  463. self.inputFileEdit = QtWidgets.QLineEdit(self.centralwidget)
  464. self.inputFileEdit.setGeometry(QtCore.QRect(310, 130, 151, 21))
  465. self.inputFileEdit.setFocusPolicy(QtCore.Qt.NoFocus)
  466. font = QtGui.QFont()
  467. font.setFamily("Arial")
  468. font.setPointSize(8)
  469. self.inputFileEdit.setFont(font)
  470. self.inputFileEdit.setObjectName("inputFileEdit")
  471. self.inputFileTool = QtWidgets.QToolButton(self.centralwidget)
  472. self.inputFileTool.setGeometry(QtCore.QRect(470, 130, 71, 21))
  473. font = QtGui.QFont()
  474. font.setFamily("Arial")
  475. font.setPointSize(10)
  476. self.inputFileTool.setFont(font)
  477. self.inputFileTool.setObjectName("inputFileTool")
  478. self.savePathLabel = QtWidgets.QLabel(self.centralwidget)
  479. self.savePathLabel.setGeometry(QtCore.QRect(180, 170, 121, 21))
  480. self.savePathLabel.setObjectName("savePathLabel")
  481. self.savePathEdit = QtWidgets.QLineEdit(self.centralwidget)
  482. self.savePathEdit.setGeometry(QtCore.QRect(310, 170, 151, 21))
  483. self.savePathEdit.setFocusPolicy(QtCore.Qt.NoFocus)
  484. font = QtGui.QFont()
  485. font.setFamily("Arial")
  486. font.setPointSize(8)
  487. self.savePathEdit.setFont(font)
  488. self.savePathEdit.setObjectName("savePathEdit")
  489. self.savePathTool = QtWidgets.QToolButton(self.centralwidget)
  490. self.savePathTool.setGeometry(QtCore.QRect(470, 170, 71, 21))
  491. font = QtGui.QFont()
  492. font.setFamily("Arial")
  493. font.setPointSize(10)
  494. self.savePathTool.setFont(font)
  495. self.savePathTool.setObjectName("savePathTool")
  496. self.startTimeLabel = QtWidgets.QLabel(self.centralwidget)
  497. self.startTimeLabel.setGeometry(QtCore.QRect(180, 210, 121, 21))
  498. self.startTimeLabel.setObjectName("startTimeLabel")
  499. self.startTimeEdit = QtWidgets.QDateTimeEdit(self.centralwidget)
  500. self.startTimeEdit.setGeometry(QtCore.QRect(310, 210, 151, 21))
  501. self.startTimeEdit.setMaximumDateTime(QtCore.QDateTime(QtCore.QDate(2025, 12, 31), QtCore.QTime(23, 59, 59)))
  502. self.startTimeEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(2023, 8, 29), QtCore.QTime(20, 0, 0)))
  503. self.startTimeEdit.setObjectName("startTimeEdit")
  504. self.endTimeLabel = QtWidgets.QLabel(self.centralwidget)
  505. self.endTimeLabel.setGeometry(QtCore.QRect(180, 250, 121, 21))
  506. self.endTimeLabel.setObjectName("endTimeLabel")
  507. self.endTimeEdit = QtWidgets.QDateTimeEdit(self.centralwidget)
  508. self.endTimeEdit.setGeometry(QtCore.QRect(310, 250, 151, 21))
  509. self.endTimeEdit.setMaximumDateTime(QtCore.QDateTime(QtCore.QDate(2025, 12, 31), QtCore.QTime(23, 59, 59)))
  510. self.endTimeEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(2023, 8, 30), QtCore.QTime(10, 0, 0)))
  511. self.endTimeEdit.setObjectName("endTimeEdit")
  512. self.platLabel = QtWidgets.QLabel(self.centralwidget)
  513. self.platLabel.setGeometry(QtCore.QRect(180, 290, 121, 21))
  514. self.platLabel.setObjectName("dianjiLabel")
  515. self.platBox = QtWidgets.QComboBox(self.centralwidget)
  516. self.platBox.setGeometry(QtCore.QRect(310, 290, 151, 21))
  517. self.platBox.addItems(['大数据平台','四情平台'])
  518. font = QtGui.QFont()
  519. font.setFamily("Arial")
  520. font.setPointSize(11)
  521. self.platBox.setFont(font)
  522. self.platBox.setObjectName("platBox")
  523. self.stm8vsLabel = QtWidgets.QLabel(self.centralwidget)
  524. self.stm8vsLabel.setGeometry(QtCore.QRect(180, 330, 121, 21))
  525. self.stm8vsLabel.setObjectName("stm8vsLabel")
  526. self.stm8vsEdit = QtWidgets.QLineEdit(self.centralwidget)
  527. self.stm8vsEdit.setGeometry(QtCore.QRect(310, 330, 151, 21))
  528. font = QtGui.QFont()
  529. font.setFamily("Arial")
  530. font.setPointSize(11)
  531. self.stm8vsEdit.setFont(font)
  532. self.stm8vsEdit.setObjectName("stm8vsEdit")
  533. font = QtGui.QFont()
  534. font.setFamily("Arial")
  535. font.setPointSize(11)
  536. self.orderLabel = QtWidgets.QLabel(self.centralwidget)
  537. self.orderLabel.setGeometry(QtCore.QRect(180, 370, 121, 21))
  538. self.orderLabel.setObjectName("dverLabel")
  539. self.orderEdit = QtWidgets.QLineEdit(self.centralwidget)
  540. self.orderEdit.setGeometry(QtCore.QRect(310, 370, 151, 21))
  541. font = QtGui.QFont()
  542. font.setFamily("Arial")
  543. font.setPointSize(11)
  544. self.orderEdit.setFont(font)
  545. self.orderEdit.setObjectName("dverEdit")
  546. self.pushButton = QtWidgets.QPushButton(self.centralwidget)
  547. self.pushButton.setGeometry(QtCore.QRect(300, 410, 111, 41))
  548. self.pushButton.setObjectName("pushButton")
  549. self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
  550. self.progressBar.setGeometry(QtCore.QRect(130, 470, 491, 31))
  551. self.progressBar.setProperty("value", 0)
  552. self.progressBar.setVisible(False)
  553. self.progressBar.setObjectName("progressBar")
  554. MainWindow.setCentralWidget(self.centralwidget)
  555. self.retranslateUi(MainWindow)
  556. self.inputFileTool.clicked.connect(self.input_file_path)
  557. self.savePathTool.clicked.connect(self.out_save_location)
  558. self.pushButton.clicked.connect(self.on_click)
  559. QtCore.QMetaObject.connectSlotsByName(MainWindow)
  560. def retranslateUi(self, MainWindow):
  561. _translate = QtCore.QCoreApplication.translate
  562. MainWindow.setWindowTitle(_translate("MainWindow", "气象站质检工具"))
  563. self.savePathTool.setText(_translate("MainWindow", "选择文件夹"))
  564. self.inputFileTool.setText(_translate("MainWindow", "选择文件"))
  565. self.pageTitleLabel.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600; color:#3a45aa;\">云飞气象站设备质检工具</span></p></body></html>"))
  566. self.savePathLabel.setText(_translate("MainWindow", "|输出文件位置:"))
  567. self.inputFileLabel.setText(_translate("MainWindow", "|输入文件位置:"))
  568. self.startTimeLabel.setText(_translate("MainWindow", "|开始时间:"))
  569. self.endTimeLabel.setText(_translate("MainWindow", "|结束时间:"))
  570. self.platLabel.setText(_translate("MainWindow", "|检验平台:"))
  571. self.stm8vsLabel.setText(_translate("MainWindow", "|主板版本号:"))
  572. self.orderLabel.setText(_translate("MainWindow", "|任务单号:"))
  573. self.pushButton.setText(_translate("MainWindow", "开始导出"))
  574. def input_file_path(self):
  575. file_path = QtWidgets.QFileDialog.getOpenFileName(None,"选取文件","./","All Files (*.xlsx;*.xls);;Text Files (*.txt);;ALL(*)")
  576. self.inputFileEdit.setText(file_path[0])
  577. self.inputFileEdit.setStyleSheet("color:black;")
  578. def out_save_location(self):
  579. fname = QtWidgets.QFileDialog.getExistingDirectory(None, '选取文件夹', './')
  580. self.savePathEdit.setText(fname)
  581. self.savePathEdit.setStyleSheet("color:black;")
  582. def on_click(self):
  583. file_path = self.inputFileEdit.text()
  584. save_path = self.savePathEdit.text()
  585. start_time = self.startTimeEdit.dateTime().toPyDateTime()
  586. end_time = self.endTimeEdit.dateTime().toPyDateTime()
  587. set_plat = self.platBox.currentText()
  588. set_stm8vs = self.stm8vsEdit.text()
  589. set_order = self.orderEdit.text()
  590. if not all ([file_path,save_path,start_time,end_time,set_stm8vs,set_order]):
  591. QtWidgets.QMessageBox.information(None, "提示", "选项未填写完整")
  592. elif end_time < start_time:
  593. QtWidgets.QMessageBox.information(None, "提示", "结束日期应在开始日期之后")
  594. else:
  595. read_dict = {}
  596. if file_path.split(".")[-1] == "xlsx":
  597. wb = openpyxl.load_workbook(file_path)
  598. sheet = wb[wb.sheetnames[0]]
  599. row_num = sheet.max_row
  600. d_list = []
  601. for row in range(2, row_num + 1):
  602. cell = sheet.cell(row, 1)
  603. try:
  604. cell_value = str(cell.value).strip()
  605. if cell_value:
  606. d_list.append(cell.value)
  607. except Exception as e:
  608. continue
  609. read_dict["设备ID"] = d_list
  610. else:
  611. xls = open_workbook(file_path)
  612. sheet_object = xls.sheets()[0]
  613. ncols = sheet_object.ncols
  614. d_list = []
  615. col_value = sheet_object.col_values(0)
  616. for d_i in col_value[1:]:
  617. try:
  618. d_i_v = str(d_i).strip()
  619. d_list.append(d_i_v)
  620. except Exception as e:
  621. continue
  622. read_dict["设备ID"] = d_list
  623. device_list = read_dict.get("设备ID")
  624. if device_list:
  625. self.inputFileTool.setEnabled(False)
  626. self.savePathTool.setEnabled(False)
  627. self.startTimeEdit.setEnabled(False)
  628. self.endTimeEdit.setEnabled(False)
  629. self.platBox.setEnabled(False)
  630. self.stm8vsEdit.setEnabled(False)
  631. self.orderEdit.setEnabled(False)
  632. self.pushButton.setEnabled(False)
  633. self.pushButton.setText("执行中...")
  634. self.runThread = SCDThread(device_list,save_path,start_time,end_time,set_plat,set_stm8vs,set_order)
  635. self.runThread.proess_signal.connect(self.set_progressbar_value)
  636. self.runThread.start()
  637. self.progressBar.setVisible(True)
  638. else:
  639. QtWidgets.QMessageBox.information(None, "提示", "输入文件无'设备ID'列或该列无数据")
  640. def set_progressbar_value(self, value):
  641. self.progressBar.setValue(value)
  642. if value == 100:
  643. QtWidgets.QMessageBox.information(None, "提示", "文件导出完毕!导出文件名:\n{}".format(save_filename))
  644. self.inputFileTool.setEnabled(True)
  645. self.inputFileEdit.setText("")
  646. self.savePathTool.setEnabled(True)
  647. self.savePathEdit.setText("")
  648. self.startTimeEdit.setEnabled(True)
  649. self.endTimeEdit.setEnabled(True)
  650. self.platBox.setEnabled(True)
  651. self.stm8vsEdit.setEnabled(True)
  652. self.stm8vsEdit.setText("")
  653. self.orderEdit.setEnabled(True)
  654. self.orderEdit.setText("")
  655. self.pushButton.setEnabled(True)
  656. self.pushButton.setText("开始导出")
  657. self.progressBar.setVisible(False)
  658. self.progressBar.setValue(0)
  659. return
  660. class SCDThread(QtCore.QThread):
  661. """涉及进度条需主界面动态执行GUI,线程执行业务逻辑,避免主页面卡死"""
  662. proess_signal = QtCore.pyqtSignal(int)
  663. def __init__(self,device_list,save_path,start_time,end_time,set_plat,set_stm8vs,set_order):
  664. super(SCDThread, self).__init__()
  665. self.save_path = save_path
  666. self.start_time = time.mktime(start_time.timetuple())
  667. self.end_time = time.mktime(end_time.timetuple())
  668. # self.start_time = 1689993000
  669. # self.end_time = 1690008000
  670. self.start_time_str = start_time.strftime("%y-%m-%d %H:%M:%S")
  671. self.end_time_str = end_time.strftime("%y-%m-%d %H:%M:%S")
  672. self.set_plat = set_plat
  673. self.set_stm8vs = set_stm8vs
  674. self.set_order = set_order
  675. self.user = parse.quote_plus("root")
  676. self.passwd = parse.quote_plus("yfkj@6020")
  677. self.myclient = pymongo.MongoClient("mongodb://{0}:{1}@8.136.98.49:57017/".format(self.user,self.passwd))
  678. self.db = self.myclient.smartfarming
  679. self.device_collection = self.db.sa_device
  680. self.qxz_collection = self.db.sa_device_qxz_data
  681. self.config = {
  682. 'host': '120.27.222.26',
  683. 'port': 3306,
  684. 'user': 'yfwlw',
  685. 'password': 'sql_yfkj_6019',
  686. 'db': 'yfwlw',
  687. 'charset': 'utf8mb4',
  688. 'cursorclass': pymysql.cursors.DictCursor,
  689. }
  690. self.connection = pymysql.connect(**self.config)
  691. self.cursor = self.connection.cursor()
  692. self.cond = QxzCand()
  693. self.mongo_ping()
  694. device_list_tp = []
  695. for d in device_list:
  696. d_id, device_id, platform = self.device_their_platform(d)
  697. device_list_tp.append(device_id)
  698. self.device_list = device_list_tp
  699. def mongo_ping(self):
  700. """mongo-ping预防连接失效"""
  701. # try:
  702. # self.myclient.admin.command('ping')
  703. # except: # "ConnectionFailure"
  704. self.myclient = pymongo.MongoClient("mongodb://{0}:{1}@8.136.98.49:57017/".format(self.user,self.passwd))
  705. self.db = self.myclient.smartfarming
  706. self.device_collection = self.db.sa_device
  707. self.qxz_collection = self.db.sa_qxz_data
  708. self.qxz_info_record_collection = self.db.sa_qxz_info_record
  709. self.qxz_base_info_collection = self.db.sa_qxz_base_info
  710. # self.sa_qxz_conf = self.db.
  711. def sql_ping(self):
  712. """mysql-ping 预防连接失效"""
  713. try:
  714. self.connection.ping()
  715. except:
  716. self.connection = pymysql.connect(**self.config)
  717. self.cursor = self.connection.cursor()
  718. def __time_dif(self,checkdatetime):
  719. """计算时间差"""
  720. nowdatetime = datetime.datetime.now()
  721. checkdatetime = datetime.datetime.strptime(checkdatetime, "%Y-%m-%d %H:%M:%S")
  722. timedif = checkdatetime - nowdatetime
  723. return timedif.days
  724. def device_their_platform(self,shortId):
  725. """确定设备所在平台以及完整设备号"""
  726. self.mongo_ping()
  727. self.sql_ping()
  728. regex = re.compile('.*{}$'.format(shortId))
  729. bd_device_dict = self.device_collection.find_one(
  730. filter = {"device_id":regex,"device_type_id":5},
  731. projection = {'_id': 0},
  732. sort = [('uptime', pymongo.DESCENDING)]
  733. )
  734. device_sql = "SELECT * FROM AppInfoManage_qxzstatus_new WHERE equip_id_id LIKE '%{}' ORDER BY upl_time DESC LIMIT 1;".format(shortId)
  735. self.cursor.execute(device_sql)
  736. sq_device_dict = self.cursor.fetchone()
  737. if bd_device_dict and sq_device_dict:
  738. bd_upltime = bd_device_dict["uptime"]
  739. sq_upltime = time.mktime(sq_device_dict["upl_time"].timetuple())
  740. if bd_upltime >= sq_upltime:
  741. d_id = bd_device_dict["id"]
  742. deviceId = bd_device_dict["device_id"]
  743. platform = "大数据平台"
  744. else:
  745. d_id = ""
  746. deviceId = sq_device_dict["equip_id_id"]
  747. platform = "四情平台"
  748. elif bd_device_dict and not sq_device_dict:
  749. d_id = bd_device_dict["id"]
  750. deviceId = bd_device_dict["device_id"]
  751. platform = "大数据平台"
  752. return d_id,deviceId,platform
  753. elif not bd_device_dict and sq_device_dict:
  754. d_id = ""
  755. deviceId = sq_device_dict["equip_id_id"]
  756. platform = "四情平台"
  757. else:
  758. d_id = ""
  759. deviceId = "平台无此设备"
  760. platform = "未知"
  761. return d_id,deviceId,platform
  762. def sim_info(self, iccid):
  763. """查询卡信息"""
  764. url = "http://8.136.98.49:10001/iotcard/platsimview/inquiries/"
  765. try:
  766. response = requests.request("POST", url, data={"iccid": iccid})
  767. except:
  768. return [0, "查询卡信息异常稍后重试"]
  769. else:
  770. res_data = json.loads(response.text)
  771. if res_data["msg"] == "success" and res_data["data"]:
  772. expiry_date = res_data["data"]["expiry_date"]
  773. if expiry_date == "未知":
  774. return [0, "未查询到卡信息"]
  775. else:
  776. time_difference = self.__time_dif(expiry_date)
  777. if time_difference >= 180:
  778. return [1, "有效期剩余{}天".format(time_difference)]
  779. elif 30 <= time_difference < 180:
  780. return [1, "有效期剩余{}天".format(time_difference)]
  781. else:
  782. return [1, "有效期剩余{}天".format(time_difference)]
  783. else:
  784. return [1, "查询无结果"]
  785. def _get_data_new(self):
  786. """获取最新设备数据信息"""
  787. pipeline = [
  788. {
  789. "$match": {
  790. "device_id": {"$in": self.device_list}
  791. }
  792. },
  793. {
  794. "$group": {
  795. "_id": {"device_id": "$device_id"},
  796. "last_msg": {"$last": "$$ROOT"}
  797. }
  798. },
  799. {
  800. "$replaceRoot": {"newRoot": "$last_msg"}
  801. }
  802. ]
  803. cursor = self.db.sa_qxz_data.aggregate(pipeline, allowDiskUse=True)
  804. data_dict = {item['device_id']: item for item in cursor}
  805. return data_dict
  806. def _get_bigdata_qxz_conf(self):
  807. data_dict = self._get_data_new()
  808. cursor = self.db.sa_qxz_conf.find({"device_id": {"$in": self.device_list}})
  809. title_name_set = set()
  810. qxz_conf_dict = {}
  811. for item in cursor:
  812. device_id = item['device_id']
  813. qxz_data = data_dict[device_id]
  814. config_dict = {}
  815. counter = Counter()
  816. for k, v in item.items():
  817. if k.startswith('e') and v and qxz_data.get(k, None):
  818. t_name = v.split('#')[0]
  819. t_index = counter.get(t_name, "")
  820. config_dict[k] = f"{t_name}#{t_index}"
  821. counter[t_name] += 1
  822. n_list = list(config_dict.values())
  823. title_name_set.update(n_list)
  824. qxz_conf_dict[device_id] = config_dict
  825. title_name_list = sorted(list(title_name_set))
  826. return title_name_list, qxz_conf_dict
  827. def get_qxz_element_data(self, device_id, conf_dict):
  828. group_dict = {
  829. "_id": "$device_id",
  830. "total_count": {"$count": {}},
  831. "uptime_list": {"$push": "$uptime"}
  832. }
  833. project_dict = {
  834. "_id": 0,
  835. "device_id": "$_id",
  836. "total_count": "$total_count",
  837. "uptime_info": {
  838. "$function": {
  839. "args": ["$uptime_list"],
  840. "lang": "js",
  841. "body": """
  842. function(uptime_list){
  843. let old_uptime = uptime_list[0];
  844. let uptime_20 = 0;
  845. let uptime_40 = 0;
  846. for (let i = 1; i < uptime_list.length; i++) {
  847. let uptime = uptime_list[i];
  848. let diff_time = uptime - old_uptime;
  849. if (diff_time < 1200){
  850. uptime_20 += 1;
  851. } else if (diff_time > 2400){
  852. uptime_40 += 1;
  853. }
  854. old_uptime = uptime;
  855. }
  856. return {"uptime_20": uptime_20, "uptime_40": uptime_40}
  857. }
  858. """
  859. }
  860. }
  861. }
  862. for ek in conf_dict.keys():
  863. group_dict[ek] = {"$push": f"${ek}"}
  864. try:
  865. k = conf_dict[ek]
  866. func_name = self.get_conf_key(k)
  867. project_dict[ek] = self.cond.func_dict[func_name](ek)
  868. except KeyError as e:
  869. continue
  870. pipeline = [
  871. {
  872. "$match": {
  873. "device_id": device_id,
  874. "uptime": {
  875. "$gte": self.start_time,
  876. "$lt": self.end_time
  877. }
  878. }
  879. },
  880. {
  881. "$sort": {"uptime": 1}
  882. },
  883. {
  884. "$project": {
  885. "device_id": "$device_id",
  886. "uptime": "$uptime",
  887. "tmp_list": {
  888. "$filter": {
  889. "input": {"$objectToArray": "$$ROOT"},
  890. "as": "item",
  891. "cond": {
  892. "$and": [
  893. {
  894. "$regexMatch": {
  895. "input": "$$item.k",
  896. "regex": "^e\d+",
  897. "options": "i"
  898. }
  899. },
  900. {
  901. "$regexMatch": {
  902. "input": "$$item.v",
  903. "regex": ".*#.*",
  904. "options": "i"
  905. }
  906. }
  907. ]
  908. }
  909. }
  910. }
  911. }
  912. },
  913. {
  914. "$addFields": {
  915. "tmp_obj": {
  916. "$arrayToObject": {
  917. "$map": {
  918. "input": "$tmp_list",
  919. "as": "item",
  920. "in": {
  921. "k": "$$item.k",
  922. "v": {
  923. "$toInt": {
  924. "$convert": {
  925. "input": {"$arrayElemAt": [{"$split": ["$$item.v", "#"]}, 0]},
  926. "to": "int",
  927. "onError": 0,
  928. "onNull": 0
  929. }
  930. # "$toDouble": {
  931. # "$arrayElemAt": [{"$split": ["$$item.v", "#"]}, 0]
  932. # }
  933. }
  934. }
  935. }
  936. }
  937. }
  938. }
  939. }
  940. },
  941. {
  942. "$replaceRoot": {
  943. "newRoot": {
  944. "$mergeObjects": ["$tmp_obj", {"device_id": "$device_id", "uptime": "$uptime"}]
  945. }
  946. }
  947. },
  948. {
  949. "$group": group_dict
  950. },
  951. {
  952. "$project": project_dict
  953. }
  954. ]
  955. print("执行之前...")
  956. cursor = self.db.sa_qxz_data.aggregate(pipeline, allowDiskUse=True)
  957. result = {k: v for item in cursor for k, v in item.items()}
  958. return result
  959. def get_qxz_volt_or_rssi_data(self):
  960. pipeline = [
  961. {
  962. "$match": {
  963. "device_id": {
  964. "$in": self.device_list
  965. },
  966. 'uptime': {
  967. '$gte': self.start_time,
  968. '$lte': self.end_time
  969. },
  970. },
  971. },
  972. {
  973. "$project": {
  974. "device_id": "$device_id",
  975. "volt": {
  976. "$toDouble": "$volt"
  977. },
  978. "rssi": {
  979. "$toDouble": "$rssi"
  980. }
  981. }
  982. },
  983. {
  984. "$group": {
  985. "_id": "$device_id",
  986. "max_volt": {
  987. "$max": "$volt"
  988. },
  989. "min_volt": {
  990. "$min": "$volt"
  991. },
  992. "max_rssi": {
  993. "$max": "$rssi"
  994. },
  995. "min_rssi": {
  996. "$min": "$rssi"
  997. }
  998. }
  999. },
  1000. {
  1001. "$project": {
  1002. "_id": 0,
  1003. "device_id": "$_id",
  1004. "volt_info": {
  1005. 'max_value': "$max_volt", 'min_value': "$min_volt",
  1006. 'status': {
  1007. "$cond": {
  1008. "if": {
  1009. "$and": [
  1010. {"$lte": ["$max_volt", 15]},
  1011. {"$gte": ["$min_volt", 11]}
  1012. ]
  1013. },
  1014. "then": 1,
  1015. "else": 0
  1016. }
  1017. }
  1018. },
  1019. "rssi_info": {
  1020. 'max_value': "$max_rssi", 'min_value': "$min_rssi",
  1021. 'status': {
  1022. "$cond": {
  1023. "if": {
  1024. "$gte": ["$min_rssi", 14]
  1025. },
  1026. "then": 1,
  1027. "else": 0
  1028. }
  1029. }
  1030. }
  1031. }
  1032. }
  1033. ]
  1034. cursor = self.qxz_info_record_collection.aggregate(pipeline, allowDiskUse=True)
  1035. result = {item['device_id']: item for item in cursor}
  1036. return result
  1037. def get_qxz_device_data(self):
  1038. pipeline = [
  1039. {
  1040. "$match": {
  1041. "device_id": {
  1042. "$in": self.device_list
  1043. }
  1044. },
  1045. },
  1046. {
  1047. "$project": {
  1048. "device_id": "$device_id",
  1049. "dver_num": "$dver_num",
  1050. "lng": {
  1051. "$convert": {
  1052. "input": "$lng",
  1053. "to": "double",
  1054. "onError": 0,
  1055. "onNull": 0
  1056. }
  1057. },
  1058. "lat": {
  1059. "$convert": {
  1060. "input": "$lat",
  1061. "to": "double",
  1062. "onError": 0,
  1063. "onNull": 0
  1064. }
  1065. }
  1066. }
  1067. },
  1068. {
  1069. "$project": {
  1070. "_id": 0,
  1071. "device_id": "$device_id",
  1072. "dver_info": {
  1073. "status": {
  1074. "$cond": {
  1075. "if": {
  1076. "$eq": ["$dver_num", self.set_stm8vs]
  1077. },
  1078. "then": 1,
  1079. "else": 0
  1080. }
  1081. },
  1082. "dver_num": "$dver_num",
  1083. "old_value": self.set_stm8vs
  1084. },
  1085. "lng_info": {
  1086. "status": {
  1087. "$cond": {
  1088. "if": {
  1089. "$and": [
  1090. {"$lte": ["$lng", 113.7869444]},
  1091. {"$gte": ["$lng", 113.7536111]}
  1092. ]
  1093. },
  1094. "then": 1,
  1095. "else": 0
  1096. }
  1097. },
  1098. "lng": "$lng"
  1099. },
  1100. "lat_info": {
  1101. "status": {
  1102. "$cond": {
  1103. "if": {
  1104. "$and": [
  1105. {"$lte": ["$lat", 35.0458333]},
  1106. {"$gte": ["$lat", 35.0125]}
  1107. ]
  1108. },
  1109. "then": 1,
  1110. "else": 0
  1111. }
  1112. },
  1113. "lat": "$lat"
  1114. }
  1115. }
  1116. }
  1117. ]
  1118. cursor = self.device_collection.aggregate(pipeline, allowDiskUse=True)
  1119. result = {item['device_id']: item for item in cursor}
  1120. return result
  1121. def get_sim_data(self):
  1122. pipeline = [
  1123. {
  1124. "$match": {
  1125. "device_id": {
  1126. "$in": self.device_list
  1127. }
  1128. }
  1129. },
  1130. {
  1131. "$project": {
  1132. "_id": 0,
  1133. "device_id": "$device_id",
  1134. "iccid": "$iccid"
  1135. }
  1136. }
  1137. ]
  1138. cursor = self.qxz_base_info_collection.aggregate(pipeline, allowDiskUse=True)
  1139. result = {item['device_id']: item["iccid"] for item in cursor}
  1140. return result
  1141. def parse_data(self, device_id, qxz_conf_dict, vr_dict, device_data_dict, sim_data):
  1142. """解析获取元素数据"""
  1143. element_dict = {}
  1144. element_dict["ID#"] = device_id
  1145. element_dict["检验项目#"] = device_id
  1146. try:
  1147. conf_dict = qxz_conf_dict[device_id]
  1148. device_data = self.get_qxz_element_data(device_id, conf_dict)
  1149. element_dict.update({conf_dict[k]: v for k, v in device_data.items() if k in conf_dict})
  1150. vr_info = vr_dict[device_id]
  1151. dd_info = device_data_dict[device_id]
  1152. element_dict["经度#"] = dd_info["lng_info"]
  1153. element_dict["纬度#"] = dd_info["lat_info"]
  1154. element_dict["固件版本号#"] = dd_info["dver_info"]
  1155. element_dict["电压#"] = vr_info["volt_info"]
  1156. element_dict["信号强度#"] = vr_info["rssi_info"]
  1157. sim_info = self.sim_info(sim_data[device_id])
  1158. element_dict["sim卡信息#"] = {
  1159. "status": sim_info[0],
  1160. "msg": sim_info[1]
  1161. }
  1162. element_dict["上传数据条数#"] = {
  1163. "total_count": device_data['total_count'],
  1164. "uptime_20": device_data["uptime_info"]["uptime_20"],
  1165. "uptime_40": device_data["uptime_info"]["uptime_40"]
  1166. }
  1167. except KeyError as e:
  1168. pass
  1169. return element_dict
  1170. def get_conf_key(self, k):
  1171. key = k.split('#')[0]
  1172. if "土壤含水率" in key:
  1173. key = "土壤含水率"
  1174. if "土壤温度" in key:
  1175. key = "土壤温度"
  1176. return key
  1177. def get_position(self, lng, lat):
  1178. if lng and lat:
  1179. try:
  1180. ret = requests.post("http://api.map.baidu.com/geocoder?location=%s,%s&coord_type=gcj02&output=json"%(lat,lng))
  1181. ret_json = json.loads(ret.text)
  1182. province, city, district = ret_json["result"]["addressComponent"]["province"], \
  1183. ret_json["result"]["addressComponent"]["city"], \
  1184. ret_json["result"]["addressComponent"]["district"]
  1185. return province + city + district
  1186. except Exception as e:
  1187. return False
  1188. else:
  1189. return False
  1190. def run(self):
  1191. """主业务逻辑,涉及进度条不能模块化,慢慢捋"""
  1192. title_name_list = ["ID#", "检验项目#", "电压#", "信号强度#", "经度#", "纬度#", "固件版本号#", "sim卡信息#",
  1193. "上传数据条数#"]
  1194. default_func_dict = {
  1195. "电压": self.cond.get_cond_volt_msg,
  1196. "信号强度": self.cond.get_cond_rssi_msg,
  1197. "经度": self.cond.get_cond_lng_msg,
  1198. "纬度": self.cond.get_cond_lat_msg,
  1199. "固件版本号": self.cond.get_cond_version_msg,
  1200. "上传数据条数": self.cond.get_time_uptime_msg,
  1201. "sim卡信息": self.cond.get_cond_sim_msg
  1202. }
  1203. head_name_list, qxz_conf_dict = self._get_bigdata_qxz_conf()
  1204. for n in head_name_list:
  1205. if n not in title_name_list:
  1206. title_name_list.append(n)
  1207. title_name_list.append("位置信息#")
  1208. # title_name_list.append("热通量#")
  1209. title_name_list.append("单台合格数#")
  1210. device_data_dict = self.get_qxz_device_data()
  1211. vr_dict = self.get_qxz_volt_or_rssi_data()
  1212. sim_data = self.get_sim_data()
  1213. proess = 0
  1214. now_time = datetime.datetime.now()
  1215. global save_filename
  1216. save_filename = self.set_order + "_" + now_time.strftime("%m%d") + ".xlsx"
  1217. save_path = os.path.join(self.save_path,save_filename)
  1218. workbook = Workbook(save_path)
  1219. worksheet = workbook.add_worksheet()
  1220. merge_title_style = workbook.add_format(merge_title_format)
  1221. toji_style = workbook.add_format(toji_format)
  1222. default_style = workbook.add_format(default_formal)
  1223. red_style = workbook.add_format(error_format)
  1224. green_style = workbook.add_format(formal_format)
  1225. yellow_style = workbook.add_format(common_format)
  1226. style_dict = {
  1227. 0: red_style,
  1228. 1: green_style,
  1229. 2: yellow_style,
  1230. 3: default_style
  1231. }
  1232. head_list = [i.split("#")[0] for i in title_name_list]
  1233. worksheet.merge_range(0, 0, 0, len(head_list) - 1, "物联网气象站设备质检表格", merge_title_style)
  1234. for index, k in enumerate(title_name_list):
  1235. value = k.split('#')[0]
  1236. worksheet.write(2, index, value, default_style)
  1237. for index, k in enumerate(title_name_list):
  1238. key = self.get_conf_key(k)
  1239. try:
  1240. value = self.cond.head_dict[key]
  1241. except KeyError as e:
  1242. value = "无判定条件"
  1243. worksheet.write(3, index, value, default_style)
  1244. row_index = 4
  1245. qualified = 0
  1246. for device_id in self.device_list:
  1247. self.mongo_ping()
  1248. element_dict = self.parse_data(device_id, qxz_conf_dict, vr_dict, device_data_dict, sim_data)
  1249. device_config = self.db.sa_qxz_conf.find_one({"device_id": device_id}, {'_id':0,'id':0})
  1250. device_data = self.db.sa_qxz_data.find({"device_id": device_id, "uptime": {"$gte": self.start_time, "$lte": self.end_time}})
  1251. # device_machine = self.db.sa_device.find_one({"device_id": device_id})
  1252. not_qualified = 0
  1253. lng = 0
  1254. lat = 0
  1255. for index, k in enumerate(title_name_list):
  1256. status, msg = 3, "无数据"
  1257. try:
  1258. value = element_dict[k]
  1259. key = self.get_conf_key(k)
  1260. if key in ["ID", "检验项目"]:
  1261. rt = {"status": 1, "msg": value}
  1262. elif key in default_func_dict:
  1263. rt = default_func_dict[key](value)
  1264. if key == "经度":
  1265. lng = value.get("lng")
  1266. if key == "纬度":
  1267. lat = value.get("lat")
  1268. else:
  1269. if key == "日照时数":
  1270. idevice_key_sun = ""
  1271. device_config = dict(device_config)
  1272. for iname, ivalue in device_config.items():
  1273. if ivalue and isinstance(ivalue, str):
  1274. if "日照时数" in ivalue:
  1275. idevice_key_sun = iname
  1276. idevice_data = []
  1277. for d in device_data:
  1278. idevice_data.append(float((d.get(idevice_key_sun)).split("#")[0]))
  1279. if max(idevice_data) > 0.1:
  1280. rt = {'status': 1, 'msg': f'最大值:{str(max(idevice_data))},最小值:{str(min(idevice_data))}'}
  1281. else:
  1282. rt = {'status': 0, 'msg': f'最大值:{str(max(idevice_data))},最小值:{str(min(idevice_data))}'}
  1283. elif key == "降雨量累计":
  1284. idevice_key_rain = ""
  1285. device_config = dict(device_config)
  1286. for iname, ivalue in device_config.items():
  1287. if ivalue and isinstance(ivalue, str):
  1288. if "降雨量累计" in ivalue:
  1289. idevice_key_rain = iname
  1290. idevice_data = []
  1291. for d in device_data:
  1292. idevice_data.append(float((d.get(idevice_key_rain)).split("#")[0]))
  1293. if max(idevice_data) > 0.1:
  1294. rt = {'status': 1, 'msg': f'最大值:{str(max(idevice_data))},最小值:{str(min(idevice_data))}'}
  1295. else:
  1296. rt = {'status': 0, 'msg': f'最大值:{str(max(idevice_data))},最小值:{str(min(idevice_data))}'}
  1297. # elif k == "热通量#":
  1298. # # 从数据中解析
  1299. # idevice_key_rain = ""
  1300. # device_config = dict(device_config)
  1301. # for iname, ivalue in device_config.items():
  1302. # if ivalue and isinstance(ivalue, str):
  1303. # if "热通量" in ivalue:
  1304. # idevice_key_rain = iname
  1305. # print(idevice_key_rain)
  1306. # idevice_data = []
  1307. # for d in device_data:
  1308. # idevice_data.append(float((d.get(idevice_key_rain)).split("#")[0]))
  1309. # if idevice_data:
  1310. # if (0 not in idevice_data) and max(idevice_data) < 500 and min(idevice_data) > -500:
  1311. # rt = {'status': 1, 'msg': f'最大值:{str(max(idevice_data))},最小值:{str(min(idevice_data))}'}
  1312. # else:
  1313. # rt = {'status': 0, 'msg': f'最大值:{str(max(idevice_data))},最小值:{str(min(idevice_data))}'}
  1314. # status, msg = rt['status'], rt['msg']
  1315. # else:
  1316. # status, msg = 0, "不合格"
  1317. else:
  1318. rt = self.cond.cond_msg_dict[key](value)
  1319. status, msg = rt['status'], rt['msg']
  1320. except Exception as e:
  1321. pass
  1322. if status == 0:
  1323. not_qualified += 1
  1324. if k == "位置信息#":
  1325. # 使用经纬度获取地理
  1326. result = self.get_position(lng, lat)
  1327. if not result:
  1328. device_tp = self.device_collection.find_one({"device_id": device_id})
  1329. if device_tp:
  1330. result = device_tp.get("province") + device_tp.get("city") + device_tp.get("district")
  1331. else:
  1332. result = ""
  1333. if result and result == "河南省新乡市原阳县":
  1334. status = 1
  1335. msg = result
  1336. else:
  1337. status = 0
  1338. msg = result
  1339. if k == "单台合格数#":
  1340. status, msg = 0, f"不合格: {not_qualified}"
  1341. if not_qualified == 0:
  1342. status, msg = 1, "合格"
  1343. column_style = style_dict[status]
  1344. worksheet.write(row_index, index, str(msg), column_style)
  1345. proess = (index + 1) / len(self.device_list) * 100
  1346. if int(proess) == 100:
  1347. self.proess_signal.emit(99)
  1348. else:
  1349. self.proess_signal.emit(int(proess))
  1350. if not_qualified == 0:
  1351. qualified += 1
  1352. row_index += 1
  1353. toji_data = [
  1354. "任务单号", self.set_order, "检验时间", self.start_time_str, self.end_time_str,
  1355. "报告日期", now_time.strftime("%y-%m-%d %H:%M:%S"), "合格数", qualified
  1356. ]
  1357. for i in range(len(head_list) - len(toji_data)):
  1358. toji_data.append(" ")
  1359. for index, k in enumerate(toji_data):
  1360. value = str(k)
  1361. worksheet.write(1, index, value, toji_style)
  1362. c_n = len(value) + 15
  1363. worksheet.set_column(index, index, c_n)
  1364. worksheet.protect(pwd_str)
  1365. workbook.close()
  1366. self.cursor.close()
  1367. self.connection.close()
  1368. self.myclient.close()
  1369. self.proess_signal.emit(100)
  1370. if __name__== "__main__":
  1371. QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
  1372. QtGui.QGuiApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
  1373. app = QtWidgets.QApplication(sys.argv)
  1374. MainWindow = QtWidgets.QMainWindow()
  1375. ui = Ui_MainWindow()
  1376. ui.setupUi(MainWindow)
  1377. MainWindow.show()
  1378. sys.exit(app.exec_())