device.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. from django.conf import settings
  4. from django.core.paginator import Paginator
  5. from django.forms.models import model_to_dict
  6. import time
  7. import os
  8. import datetime
  9. import uuid
  10. import json
  11. import logging
  12. import requests
  13. from smartfarming.utils import get_addr_by_lag_lng
  14. from smartfarming.serializers.device_serializers import DeviceSerializers
  15. from smartfarming.models.device import MongoDevice, MongoCBDData, MongoSCDData, MongoXYCBData
  16. from smartfarming.models.worm_forecast import MongoCBDphoto
  17. from smartfarming.models.weather import (
  18. MongoQXZ_Base_Info,
  19. MongoQXZ_Alarm_Log_New,
  20. MongoQXZ_Conf,
  21. QXZdata_New,
  22. MongoQXZ_Alarm,
  23. QXZThresholdWarning
  24. )
  25. from django.db.models import Q
  26. from smartfarming.qxz import data_deal
  27. from collections import Counter, defaultdict
  28. from smartfarming.models.device import MongoDevice, DevicePestWarning, MongoDeviceType
  29. from kedong.decoration import kedong_deco, PortError
  30. from django.core.paginator import Paginator
  31. logger = logging.getLogger("data_ingestion")
  32. config_dict = settings.CONFIG
  33. device_type_en = config_dict.get("device_type_en")
  34. device_type_zh = config_dict.get("device_type_zh")
  35. class CbdScdXyDeviceSaveAPIView(APIView):
  36. permission_classes = []
  37. authentication_classes = []
  38. def post(self, request):
  39. # 测报灯 杀虫灯 性诱 设备及数据入库
  40. try:
  41. request_data = request.body
  42. data = json.loads(request_data)
  43. logger.warning(f"测报灯 杀虫灯 性诱 设备及数据入库原数据: {data}")
  44. topic = data.get("topic")
  45. payload = data.get("payload")
  46. cmd = payload.get("cmd")
  47. topic_msg = topic.split("/")
  48. now = int(time.time())
  49. if topic_msg and len(topic_msg) == 5 and cmd:
  50. device_id = topic_msg[-1]
  51. try:
  52. device_type = topic_msg[2]
  53. device_type_id = device_type_en.get(device_type)
  54. if device_type_id == 2:
  55. model = MongoSCDData
  56. elif device_type_id == 3:
  57. model = MongoCBDData
  58. elif device_type_id == 4:
  59. model = MongoXYCBData
  60. # 在设备信息表中查找是否有数据,如果没有数据则增加
  61. device_name = device_type_zh.get(str(device_type_id))
  62. device, is_created = MongoDevice.objects.get_or_create(
  63. device_id = device_id,
  64. defaults={
  65. "device_id": device_id,
  66. "device_type_id": device_type_id,
  67. "addtime": now
  68. }
  69. )
  70. if is_created:
  71. device.device_name = device_name
  72. device.save()
  73. logger.warning(f"新设备:{device_type} {device_id} 入库成功")
  74. # 获取数据并更新设备
  75. if cmd == "data":
  76. ext = payload.get("ext")
  77. if ext:
  78. # 获取设备上报的时间,同步设备
  79. try:
  80. stamp = ext.get("stamp")
  81. uptime = int((datetime.datetime.strptime(stamp, "%Y%m%d%H%M%S")).timestamp())
  82. except Exception as e:
  83. logger.error(f"同步设备时间失败:{device_id} {e}")
  84. # 增加设备数据
  85. model.objects.create(
  86. device_id = device.id,
  87. device_data = str(ext),
  88. addtime = now
  89. )
  90. lng = ext.get("lng")
  91. lat = ext.get("lat")
  92. dver_num = ext.get("dver")
  93. device.device_status = 1
  94. device.uptime = uptime
  95. if dver_num:
  96. device.dver_num = dver_num
  97. if lng and lat and dver_num and device.gps != 0:
  98. device.lng = lng
  99. device.lat = lat
  100. # 根据经纬度获取省市级
  101. is_success, province, city, district = get_addr_by_lag_lng(lat, lng)
  102. if is_success:
  103. # 更新地理位置坐标
  104. device.province = province
  105. device.city = city
  106. device.district = district
  107. device.save()
  108. elif cmd == "offline":
  109. ext = data.get("ext")
  110. if ext:
  111. # 增加设备数据
  112. model.objects.create(
  113. device_id=device_id,
  114. device_data = str(ext),
  115. addtime=now
  116. )
  117. # 更新设备状态
  118. device = MongoDevice.objects.filter(device_id=device_id).first()
  119. device.device_status = 0
  120. device.save()
  121. return Response({"code": 0, "msg": "success"})
  122. except Exception as e:
  123. logger.error(f"测报灯设备 {device_id} 处理上报数据或增加设备失败,错误原因:{e.args}")
  124. return Response({"code": 2, "msg": f"处理测报灯上报数据失败 {device_id}"})
  125. else:
  126. return Response({"code": 2, "msg": "请核对数据结构"})
  127. except Exception as e:
  128. logger.error(f"测报灯、杀虫灯、性诱设备 {e.args}")
  129. return Response({"code": 2, "msg": "failer"})
  130. class CbdPhotoAPIView(APIView):
  131. permission_classes = []
  132. authentication_classes = []
  133. def post(self, request):
  134. try:
  135. request_data = request.body
  136. request_data = json.loads(request_data)
  137. logger.warning(f"测报灯图片数据入库原数据: {request_data}")
  138. device_id = request_data.get("imei")
  139. device = MongoDevice.objects.filter(device_id=device_id)
  140. media = config_dict.get("media")
  141. img_content_url = f'{config_dict.get("image_url").get("image")}/media'
  142. if device:
  143. device = device.first()
  144. d_id = device.id
  145. # 把原图下载到本地
  146. result_image = request_data.get("Image")
  147. addr = config_dict.get("oss") + result_image if not result_image.startswith("http") else result_image
  148. inden_path = f"{media}/cbd/{device.device_id}"
  149. os.makedirs(inden_path) if not os.path.exists(inden_path) else None
  150. stamp = int(datetime.datetime.now().timestamp())
  151. unique_id = uuid.uuid4()
  152. combined_id = str(stamp) + "-" + str(unique_id)
  153. addr_org = os.path.join(inden_path, f"{combined_id}.jpg")
  154. remote_content = requests.get(addr).content
  155. with open(addr_org, "wb") as f:
  156. f.write(remote_content)
  157. # 把识别后的图片下载到本地
  158. result_temp = request_data.get("Result_image")
  159. indentify = config_dict.get("oss") + result_temp if not result_temp.startswith("http") else result_temp
  160. inden_path_tp = f"{media}/result/cbd/{device.device_id}"
  161. os.makedirs(inden_path_tp) if not os.path.exists(inden_path_tp) else None
  162. stamp = int(datetime.datetime.now().timestamp())
  163. unique_id = uuid.uuid4()
  164. combined_id = str(stamp) + "-" + str(unique_id)
  165. indentify_photo = os.path.join(inden_path_tp, f"{combined_id}.jpg")
  166. indentify_remote_content = requests.get(indentify).content
  167. with open(indentify_photo, "wb") as f:
  168. f.write(indentify_remote_content)
  169. data = {
  170. "device_id": d_id,
  171. "addr": addr_org.replace(media, "/media"),
  172. "indentify_photo":indentify_photo.replace(media, img_content_url),
  173. "indentify_result": request_data.get("Result"),
  174. "label": request_data.get("Result_code"),
  175. "photo_status": 1,
  176. "uptime": int(time.time()),
  177. "addtime": int(time.time())
  178. }
  179. photo = MongoCBDphoto(**data)
  180. photo.save()
  181. return Response({"code": 0, "msg": "success"})
  182. else:
  183. return Response({"code": 2, "msg": "该项目不存在此设备"})
  184. except Exception as e:
  185. logger.error(f"测报灯图片入库失败 {e.args}")
  186. return Response({"code": 2, "msg": "failer"})
  187. class QxzDeviceAddAPIViw(APIView):
  188. permission_classes = []
  189. authentication_classes = []
  190. def post(self, request):
  191. # 气象站上传数据
  192. try:
  193. request_data = request.body
  194. request_data = json.loads(request_data)
  195. logger.error(f"气象站源数据:{request_data}")
  196. device_id = request_data.get("StationID")
  197. uptime = request_data.get("MonitorTime")
  198. data = request_data.get("data")
  199. terminalStatus = request_data.get("terminalStatus")
  200. cmd = request_data.get("cmd")
  201. up = uptime.replace(" ", "")
  202. uptime_tp = int((datetime.datetime.strptime(up, "%Y-%m-%d%H:%M:%S")).timestamp())
  203. if device_id:
  204. # 获取该设备的预警配置数据
  205. alarm = MongoQXZ_Alarm.objects.filter(device_id=device_id)
  206. qxz_e_conf = MongoQXZ_Conf.objects.filter(device_id=device_id)
  207. qxz_e_conf = qxz_e_conf.first() if qxz_e_conf else None
  208. mongo_device = MongoDevice.objects.filter(device_id=device_id)
  209. if mongo_device:
  210. mongo_device = mongo_device.first()
  211. if not qxz_e_conf:
  212. logger.error(f"该设备未配置预警阀值: {mongo_device.device_id}")
  213. return Response({"code": 2, "msg": "该设备未配置预警阀值"})
  214. if data:
  215. qxz_e_conf = model_to_dict(qxz_e_conf)
  216. qx_ek = {}
  217. result_tp_fin = ""
  218. for i in data:
  219. tp_value = i.get("eValue")
  220. if tp_value:
  221. ek = i.get("eKey")
  222. qx_ek[ek] = f"{tp_value}#{i.get('eNum')}#{ek}"
  223. if alarm:
  224. # 存在预警配置文件, 先查看预警配置文件中是否有配置 -- "0#6" 表示大于6则报警 "1#5" 表示小于5报警 "0#" 表示不配置
  225. alarms = alarm.first()
  226. alarm_config = eval(alarms.conf)
  227. dat = alarm_config.get("dat")
  228. for m, n in dat.items():
  229. n_sp = n.split("#")
  230. if n_sp[1]:
  231. if ek == m:
  232. # 查询具体含义
  233. zh = qxz_e_conf.get(m)
  234. zh_k = zh.split("#")
  235. result = ""
  236. if n_sp[0] == "1":
  237. if float(tp_value) > float(n_sp[1]):
  238. # 组织预警信息
  239. result = f"为{tp_value},大于{n_sp[1]}"
  240. elif n_sp[0] == "0":
  241. if float(tp_value) < float(n_sp[1]):
  242. result = f"为{tp_value},小于{n_sp[1]}"
  243. if result:
  244. QXZThresholdWarning.objects.create(
  245. device_id=device_id,
  246. warning_content= "大于预警" if n_sp[0] == "1" else "小于预警",
  247. ekey=zh,
  248. set_value=n_sp[1],
  249. current_value=tp_value,
  250. upltime=uptime_tp
  251. )
  252. result_tp = f"{zh_k[0]}{result}{zh_k[1]},"
  253. result_tp_fin += result_tp
  254. if result_tp_fin:
  255. alarm_new = MongoQXZ_Alarm_Log_New()
  256. alarm_new.warning_content = result_tp_fin
  257. alarm_new.upl_time = uptime_tp
  258. alarm_new.device_id = mongo_device.id
  259. alarm_new.warning_name = str(mongo_device.device_type_id) # 设备类型ID
  260. alarm_new.save()
  261. logger.error(f"产生预警:{device_id}")
  262. # 30分钟上报一次的数据
  263. qx_ek["device_id"] = device_id
  264. qx_ek["uptime"] = uptime_tp
  265. qxz_data = QXZdata_New(**qx_ek)
  266. qxz_data.save()
  267. mongo_device.uptime=uptime_tp
  268. mongo_device.device_status=1
  269. mongo_device.save()
  270. return Response({"code": 0, "msg": "success"})
  271. if terminalStatus:
  272. base_info_obj, is_created = MongoQXZ_Base_Info.objects.update_or_create(
  273. device_id=device_id,
  274. defaults={
  275. "volt": terminalStatus.get("VOLT"),
  276. "rssi": terminalStatus.get("RSSI"),
  277. "uptime": uptime_tp
  278. }
  279. )
  280. iccid = terminalStatus.get("ICCID")
  281. lng = terminalStatus.get("longitude")
  282. lat = terminalStatus.get("latitude")
  283. led = terminalStatus.get("Dotled")
  284. dver = terminalStatus.get("Version")
  285. device, is_created = MongoDevice.objects.get_or_create(device_id=device_id)
  286. if iccid:
  287. base_info_obj.iccid = iccid
  288. if lng:
  289. base_info_obj.lng = lng
  290. device.lng = lng
  291. if lat:
  292. base_info_obj.lat = lat
  293. device.lat = lat
  294. if led:
  295. base_info_obj.led = led
  296. if dver:
  297. base_info_obj.dver = dver
  298. # 如果经纬度均存在
  299. if lat and lng:
  300. is_success, province, city, district = get_addr_by_lag_lng(lat, lng)
  301. if is_success:
  302. device.province = province
  303. device.city = city
  304. device.district = district
  305. base_info_obj.save()
  306. device.uptime = uptime_tp
  307. device.save()
  308. return Response({"code": 0, "msg": "success"})
  309. if cmd:
  310. ext = request_data.get("ext")
  311. imei = ext.get("imei")
  312. device_info = MongoDevice.objects.get(device_id=imei)
  313. if cmd == "online":
  314. device_info.device_status = 1
  315. if cmd == "offline":
  316. device_info.device_status = 0
  317. device_info.save()
  318. except Exception as e:
  319. logger.error(f"气象站设备 {device_id} 处理上报数据或增加设备失败,错误原因:{e.args}")
  320. return Response({"code": 2, "msg": "failer"})
  321. class DeviceListAPIView(APIView):
  322. def post(self, request):
  323. # 设备列表
  324. request_data = request.data
  325. device_id = request_data.get("device_id")
  326. device_status = request_data.get("device_status")
  327. search = request_data.get("search")
  328. page_num = int(request_data.get("pagenum")) if request_data.get("pagenum") else 1
  329. page_size = int(request_data.get("pagesize")) if request_data.get("pagesize") else 10
  330. if device_id:
  331. queryset = MongoDevice.objects.filter(device_id=device_id).order_by("-uptime")
  332. elif device_status:
  333. queryset = MongoDevice.objects.filter(device_status=device_status).order_by("-uptime")
  334. elif search:
  335. queryset = MongoDevice.objects.filter(Q(device_name__icontains=search) | Q(device_id__icontains=search))
  336. else:
  337. queryset = MongoDevice.objects.all().order_by("-uptime")
  338. total_obj = queryset.count()
  339. paginator = Paginator(queryset, page_size)
  340. page_obj = paginator.get_page(page_num)
  341. serializers = DeviceSerializers(page_obj, many=True)
  342. return Response({"code": 0, "msg": "success", "data": serializers.data, "count": total_obj})
  343. class DeviceChangeAPIView(APIView):
  344. def post(self, request):
  345. # 修改设备信息
  346. request_data = request.data
  347. device_name = request_data.get("device_name")
  348. device_id = request_data.get("device_id")
  349. lng = request_data.get("lng")
  350. lat = request_data.get("lat")
  351. device = MongoDevice.objects.get(device_id=device_id)
  352. if device_name:
  353. device.device_name = device_name
  354. if lng and lat:
  355. device.lng = lng
  356. device.lat = lat
  357. is_success, province, city, district = get_addr_by_lag_lng(lat, lng)
  358. if is_success:
  359. # 更新地理位置坐标
  360. device.province = province
  361. device.city = city
  362. device.district = district
  363. device.save()
  364. return Response({"code": 0, "msg": "success"})
  365. class DeviceListInfoAPIView(APIView):
  366. def post(self, request):
  367. # 设备列表
  368. request_data = request.data
  369. device_id = request_data.get("device_id")
  370. device_status = request_data.get("device_status")
  371. search = request_data.get("search")
  372. page_num = int(request_data.get("pagenum")) if request_data.get("pagenum") else 1
  373. page_size = int(request_data.get("pagesize")) if request_data.get("pagesize") else 10
  374. if device_id:
  375. queryset = MongoDevice.objects.filter(device_id=device_id).order_by("-uptime")
  376. elif device_status:
  377. queryset = MongoDevice.objects.filter(device_status=device_status).order_by("-uptime")
  378. elif search:
  379. queryset = MongoDevice.objects.filter(Q(device_name__icontains=search) | Q(device_id__icontains=search))
  380. else:
  381. queryset = MongoDevice.objects.all().order_by("-uptime")
  382. total_obj = queryset.count()
  383. paginator = Paginator(queryset, page_size)
  384. page_obj = paginator.get_page(page_num)
  385. serializers = DeviceSerializers(page_obj, many=True)
  386. return Response({"code": 0, "msg": "success", "data": serializers.data, "count": total_obj})
  387. class DeviceListAPIView(APIView):
  388. def post(self, request):
  389. queryset = MongoDevice.objects.order_by('-id')
  390. type_dict = {d.id: d.type_name for d in MongoDeviceType.objects.all()}
  391. result = []
  392. offline_list = []
  393. type_counter = Counter()
  394. device_dict = defaultdict(list)
  395. for item in queryset:
  396. device_info = item
  397. device_type_id = device_info.device_type_id
  398. device_status = device_info.device_status
  399. is_offline = False if device_status == 1 else True
  400. device_id = device_info.device_id
  401. if is_offline:
  402. offline_list.append(device_id)
  403. type_counter[device_type_id] += 1
  404. device_dict[device_type_id].append(device_id)
  405. coordinates = ""
  406. lng = device_info.lng
  407. lat = device_info.lat
  408. if not (lng and lat):
  409. continue
  410. coordinates = f"[{str(float(lng))},{str(float(lat))}]"
  411. device_name = device_info.device_name
  412. result.append({
  413. 'ld_id': item.id,
  414. 'device_id': device_id,
  415. 'device_name': device_name or device_id,
  416. 'tpye_name': type_dict[device_info.device_type_id],
  417. 'device_type_id': device_type_id,
  418. 'coordinates': coordinates,
  419. 'offline': False if device_status == 1 else True,
  420. 'is_warning': False
  421. })
  422. statistic_list = []
  423. for k, v in type_counter.items():
  424. statistic_list.append({
  425. 'type_id': k,
  426. 'type_count': v,
  427. 'type_name': type_dict[k]
  428. })
  429. warning_model_dict = {
  430. 3: DevicePestWarning
  431. }
  432. warning_list = []
  433. for k, v in device_dict.items():
  434. try:
  435. model_obj = warning_model_dict[k]
  436. except KeyError as e:
  437. continue
  438. war_list = [d.device_id for d in model_obj.objects.filter(device_id__in=v, status=0)]
  439. if war_list:
  440. warning_list.extend(war_list)
  441. for item in result:
  442. device_id = item['device_id']
  443. if device_id in warning_list:
  444. item['is_warning'] = True
  445. warn_and_off = set(warning_list) & set(offline_list)
  446. data = {
  447. "statistic": statistic_list,
  448. 'offline': {
  449. 'count': len(offline_list),
  450. 'result': offline_list
  451. },
  452. "waring": {
  453. 'count': len(warning_list),
  454. 'result': warning_list
  455. },
  456. "warn_and_off": {
  457. 'count': len(warn_and_off),
  458. 'result': warning_list
  459. },
  460. "data": result
  461. }
  462. return Response({"code": 0, "message": "success", "data": data})