device.py 19 KB

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