CronCloudPhotoController.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : CronCloudPhotoController.py
  4. @Time : 2022/10/24 15:48
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import datetime
  10. import logging
  11. import os
  12. import time
  13. import traceback
  14. import cv2
  15. from django.db import transaction
  16. from django.views import View
  17. from Ansjer.config import PUSH_CLOUD_PHOTO, ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, PUSH_BUCKET
  18. from Model.models import UidSetModel, DeviceCloudPhotoInfo, DevicePicturePushInfo
  19. from Object.AWS.AmazonS3Util import AmazonS3Util
  20. from Object.RedisObject import RedisObject
  21. from Object.ResponseObject import ResponseObject
  22. from Object.utils import LocalDateTimeUtil
  23. from Service.EquipmentInfoService import EquipmentInfoService
  24. LOGGER = logging.getLogger('info')
  25. UID_KEY = 'ANSJER:UID:SET:INFO'
  26. class CronCloudPhotoView(View):
  27. def get(self, request, *args, **kwargs):
  28. request.encoding = 'utf-8'
  29. operation = kwargs.get('operation')
  30. return self.validation(request.GET, request, operation)
  31. def post(self, request, *args, **kwargs):
  32. request.encoding = 'utf-8'
  33. operation = kwargs.get('operation')
  34. return self.validation(request.POST, request, operation)
  35. def validation(self, request_dict, request, operation):
  36. response = ResponseObject()
  37. if operation == 'get-photo':
  38. return self.get_photo(response)
  39. elif operation == 'cache-uid-set':
  40. return self.cache_photo_uid_set(response)
  41. elif operation == 'generate-video':
  42. return self.generate_video(response)
  43. else:
  44. return response.json(404)
  45. @classmethod
  46. def get_photo(cls, response):
  47. """
  48. 定时获取设备消息推送图
  49. """
  50. try:
  51. redis = RedisObject().CONN
  52. uid_set_cache = redis.lrange(UID_KEY, 0, -1)
  53. if not uid_set_cache:
  54. return response.json(0)
  55. uid_set_cache = list(uid_set_cache)
  56. today = datetime.date.today()
  57. time_stamp = cls.get_month_stamp()
  58. now_time = int(time.time())
  59. s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME)
  60. for item in uid_set_cache:
  61. try:
  62. eq_qs = EquipmentInfoService.get_equipment_info_model(str(today))
  63. item = str(item, encoding="utf-8")
  64. eq_qs = eq_qs.filter(event_time__gt=time_stamp, is_st=1, device_uid=item) \
  65. .values('device_uid', 'channel', 'event_time', 'device_nick_name')
  66. count = eq_qs.count()
  67. page = int(count / 2) if count > 1 else count
  68. redis.lrem(UID_KEY, item, 0)
  69. if page == 0:
  70. continue
  71. eq_qs = eq_qs[(page - 1) * 1:page * 1]
  72. eq_vo = eq_qs[0]
  73. file_path = '{uid}/{channel}/{event_time}.jpeg'.format(uid=eq_vo['device_uid'],
  74. channel=eq_vo['channel'],
  75. event_time=eq_vo['event_time'])
  76. s3.copy_obj(PUSH_BUCKET, PUSH_CLOUD_PHOTO, file_path)
  77. push_data = {'type': 0, 'uid': eq_vo['device_uid'], 'channel': eq_vo['channel'],
  78. 'event_time': eq_vo['event_time'], 'updated_time': now_time, 'created_time': now_time,
  79. 'device_nick_name': eq_vo['device_nick_name']}
  80. DevicePicturePushInfo.objects.create(**push_data)
  81. except Exception as e:
  82. LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  83. continue
  84. return response.json(0)
  85. except Exception as e:
  86. print(e)
  87. LOGGER.info('--->抽取推送图片异常:{}'.format(traceback.format_exc()))
  88. return response.json(177, repr(e))
  89. @classmethod
  90. def cache_photo_uid_set(cls, response):
  91. """
  92. 缓存uid_set信息
  93. """
  94. try:
  95. photo_qs = DeviceCloudPhotoInfo.objects.filter(status=1).values('uid')
  96. if not photo_qs.exists():
  97. return response.json(0)
  98. redis = RedisObject()
  99. for item in photo_qs:
  100. uid_set_qs = UidSetModel.objects.filter(uid=item['uid'], detect_status=1)
  101. if not uid_set_qs:
  102. continue
  103. redis.CONN.rpush(UID_KEY, item['uid'])
  104. return response.json(0)
  105. except Exception as e:
  106. print(e)
  107. LOGGER.info('--->获取uid_set信息异常:{}'.format(traceback.format_exc()))
  108. return response.json(177, repr(e))
  109. @classmethod
  110. def generate_video(cls, response):
  111. """
  112. 生成视频并存库
  113. """
  114. try:
  115. photo_qs = DeviceCloudPhotoInfo.objects.filter(status=1).values('uid', 'user_id')
  116. if not photo_qs.exists():
  117. return response.json(0)
  118. # 获取当前项目路径
  119. poj_path = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
  120. time_stamp = cls.get_month_stamp()
  121. s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME)
  122. now_time = int(time.time())
  123. for item in photo_qs:
  124. try:
  125. with transaction.atomic():
  126. picture_qs = DevicePicturePushInfo.objects.filter(uid=item['uid'], event_time__gt=time_stamp,
  127. type=0) \
  128. .values('uid', 'channel', 'event_time', 'device_nick_name')
  129. if not picture_qs.exists():
  130. continue
  131. device_nickname = picture_qs[0]['device_nick_name']
  132. pic_list = cls.download_push_picture(s3, item['uid'], poj_path, picture_qs)
  133. video_path = poj_path + r'\Ansjer\file\video.mp4' # 输出视频的保存路径
  134. cls.picture_synthesis_video(video_path, poj_path, pic_list) # 图片合成视频
  135. video_name = datetime.datetime.now().strftime('%Y%m')
  136. data = open(video_path, 'rb')
  137. key = '{}/video/{}.mp4'.format(item['uid'], video_name)
  138. s3.upload_file_obj(PUSH_CLOUD_PHOTO, key, data) # 将视频资源上传至S3保存
  139. os.remove(video_path) # 上传完成删除本地资源
  140. push_data = {'type': 1, 'uid': item['uid'], 'channel': 1,
  141. 'event_time': int(video_name), 'updated_time': now_time, 'created_time': now_time,
  142. 'device_nick_name': device_nickname, 'user_id': item['user_id']}
  143. DevicePicturePushInfo.objects.create(**push_data)
  144. except Exception as e:
  145. LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  146. continue
  147. return response.json(0)
  148. except Exception as e:
  149. print(e)
  150. LOGGER.info('--->图片合成视频异常:{}'.format(traceback.format_exc()))
  151. return response.json(177)
  152. @staticmethod
  153. def download_push_picture(s3, uid, dir_url, picture_qs):
  154. """
  155. 下载推送图片,讲下载资源保存到项目本地
  156. @param s3: s3对象
  157. @param uid: 设备uid
  158. @param dir_url: 项目文件路径
  159. @param picture_qs: 消息推送图片对象
  160. @return: pic_list 图片文件名集合
  161. """
  162. pic_list = []
  163. for pic in picture_qs:
  164. path = dir_url + r'\Ansjer\file\{}.jpeg'.format(pic['event_time'])
  165. s3_key = '{}/{}/{}.jpeg'.format(uid, pic['channel'], pic['event_time'])
  166. s3.download_object(PUSH_CLOUD_PHOTO, s3_key, path)
  167. pic_list.append('{}.jpeg'.format(pic['event_time']))
  168. return pic_list
  169. @staticmethod
  170. def picture_synthesis_video(video_path, poj_path, pic_list):
  171. """
  172. 图片合成视频
  173. @param video_path: 输出视频的保存路径
  174. @param poj_path: 项目路径
  175. @param pic_list: 图片文件名集合
  176. @return:
  177. """
  178. if not pic_list:
  179. raise Exception('this pic_list is null.')
  180. fps = 1 # 帧率
  181. img_path = poj_path + r'\Ansjer\file\{}'.format(pic_list[0])
  182. image = cv2.imread(img_path)
  183. size = image.shape
  184. w = size[1] # 宽度
  185. h = size[0] # 高度
  186. img_size = (w, h) # 图片尺寸
  187. fourcc = cv2.VideoWriter_fourcc(*"mp4v")
  188. video_writer = cv2.VideoWriter(video_path, fourcc, fps, img_size)
  189. for item in pic_list:
  190. img_path = poj_path + r'\Ansjer\file\{}'.format(item)
  191. frame = cv2.imread(img_path)
  192. if frame is None:
  193. continue
  194. frame = cv2.resize(frame, img_size) # 生成视频 图片尺寸和设定尺寸相同
  195. video_writer.write(frame) # 将图片写进视频里
  196. os.remove(img_path)
  197. video_writer.release() # 释放资源
  198. @staticmethod
  199. def get_month_stamp():
  200. """
  201. 获取当月开始时间戳
  202. """
  203. now_month = LocalDateTimeUtil.get_cur_month_start()
  204. start_time = "{} 00:00:00".format(str(now_month))
  205. time_array = time.strptime(start_time, "%Y-%m-%d %H:%M:%S")
  206. # 转换为时间戳
  207. return int(time.mktime(time_array))