device.py 23 KB

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