device.py 22 KB

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