camera_manage.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. import re
  2. import requests
  3. import time
  4. import ast
  5. import os
  6. import datetime
  7. import uuid
  8. from PIL import Image
  9. from io import BytesIO
  10. from django.conf import settings
  11. from django.db.models import Count
  12. from django.core.paginator import Paginator
  13. from django.db import transaction
  14. from smartfarming.api.views.forecast.all_dict import insect_dict, attract_discern
  15. from smartfarming.models.sim_card import MongoMsg_Conf
  16. from smartfarming.models.device import MongoDevice
  17. from smartfarming.models.camera import MongoCameraPhoto, MongoCameraData, MongoCameraAccount
  18. from smartfarming.serializers.device_serializers import DeviceSerializers
  19. from smartfarming.utils import bindDeviceLive, getLive, controlMove, modify_live_time, off_on_live, setDeviceSnap, getKitToken, getRecord
  20. from kedong.tools import RedisPool
  21. from kedong.decoration import kedong_deco, PortError
  22. from smartfarming.api.views.camera.cameraserializers import (
  23. MongoCameraPhotoSerializers,
  24. MongoDeviceCameraSerializers
  25. )
  26. config_dict = settings.CONFIG
  27. @kedong_deco(login_required=True)
  28. def list_camera(request):
  29. # 获取监控设备列表
  30. post_info = request.POST
  31. device_id = post_info.get('device_id')
  32. page_num = int(post_info.get('page', 1))
  33. page_size = int(post_info.get('page_size', 10))
  34. queryset = MongoDevice.objects.filter(device_type_id=6).order_by("-uptime")
  35. if device_id:
  36. queryset = queryset.filter(device_id=device_id)
  37. paginator = Paginator(queryset, page_size)
  38. page_obj = paginator.get_page(page_num)
  39. serializers = MongoDeviceCameraSerializers(page_obj, many=True)
  40. datas = {"data": serializers.data, "counts": queryset.count()}
  41. return datas
  42. @kedong_deco(login_required=True)
  43. def addr_camera_list(request):
  44. """
  45. 获取监控设备播放地址
  46. 参数:
  47. device_id 必传 (string) 监控设备的序列号
  48. 返回值:
  49. {
  50. "data": {
  51. "hls": "http://test.ys7.com:66/openlive/b475942b03544a5aa35b651670d8712c.m3u8", HLS流畅直播地址
  52. "hlsHd": "http://test.ys7.com:66/openlive/b475942b03544a5aa35b651670d8712c.hd.m3u8", HLS高清直播地址
  53. "rtmp": "rtmp://10.82.0.190:1935/openlive/b475942b03544a5aa35b651670d8712c", RTMP流畅直播地址
  54. "rtmpHd": "rtmp://10.82.0.190:1935/openlive/b475942b03544a5aa35b651670d8712c.hd" RTMP高清直播地址
  55. }
  56. "errorCode": 0,
  57. "message": "",
  58. "formError": {}
  59. }
  60. """
  61. try:
  62. if 'HTTP_X_FORWARDED_FOR' in request.META:
  63. ip = request.META['HTTP_X_FORWARDED_FOR']
  64. else:
  65. ip = request.META['HTTP_X_REAL_IP']
  66. except Exception as KeyError:
  67. ip = request.META['REMOTE_ADDR']
  68. device_id = request.POST.get('device_id')
  69. try:
  70. addr = MongoCameraData.objects.get(device_id=device_id).device_info
  71. except:
  72. addr = {}
  73. return addr
  74. @kedong_deco(login_required=True)
  75. def ctrl_camera(request):
  76. """
  77. 控制监控设备转动 :
  78. 参数:
  79. device_id 必传 (string) 监控设备的序列号
  80. ctrl 必传 (string) 操作指令 move 控制球机转动 stop 停止球机转动
  81. movenum ctrl=move时必传(string) 0-上,1-下,2-左,3-右,8-放大,9-缩小
  82. 返回值:
  83. {
  84. "data": success, success成功 default失败
  85. "errorCode": 0,
  86. "message": "",
  87. "formError": {}
  88. }
  89. """
  90. device_id = request.POST.get('device_id')
  91. ctrl = request.POST.get('ctrl')
  92. account_id = MongoCameraData.objects.filter(device_id=device_id).first()
  93. if not account_id:
  94. raise PortError("","未找到此设备")
  95. camera_query = MongoCameraAccount.objects.filter(id=int(account_id.account_id)).first()
  96. if not camera_query:
  97. raise PortError("","未找到此账号")
  98. channelNo = "1"
  99. if device_id.find("-") != -1:
  100. channelNo = device_id.split("-")[1]
  101. device_id = device_id.split("-")[0]
  102. # 操作命令:0-上,1-下,2-左,3-右,4-左上,5-左下,6-右上,7-右下,8-放大,9-缩小,10-近焦距,11-远焦距
  103. if ctrl == "move":
  104. dire = request.POST.get('movenum')
  105. # 增加大华相机操作功能
  106. if camera_query.account_type == 1:
  107. if dire not in ("0","1","2","3","8","9"):
  108. raise PortError("movenum","暂不支持其它指令")
  109. appId = camera_query.app_key
  110. appSecret = camera_query.app_secret
  111. result = controlMove(appId,appSecret,device_id,dire,channelNo)
  112. code = result.get("result").get("code")
  113. if code == "0":
  114. return True
  115. else:
  116. return {"errorCode": 2, "msg": result.get("result").get("msg")}
  117. else:
  118. accessToken = camera_query.token
  119. ctrl_url = 'https://open.ys7.com/api/lapp/device/ptz/start'
  120. speed = '1'
  121. data = {'accessToken':accessToken, 'deviceSerial':device_id, 'channelNo':channelNo, 'speed':speed, 'direction':dire}
  122. res1 = requests.post(ctrl_url,data=data)
  123. elif ctrl == "stop":
  124. time.sleep(0.4)
  125. # 增加大华相机操作功能
  126. if camera_query.account_type == 1:
  127. dire = "10"
  128. appId = camera_query.app_key
  129. appSecret = camera_query.app_secret
  130. result = controlMove(appId,appSecret,device_id,dire,channelNo)
  131. code = result.get("result").get("code")
  132. if code == "0":
  133. return True
  134. else:
  135. return {"errorCode": 2, "msg": result.get("result").get("msg")}
  136. else:
  137. accessToken = camera_query.token
  138. ctrl_url = 'https://open.ys7.com/api/lapp/device/ptz/stop'
  139. data = {'accessToken':accessToken, 'deviceSerial':device_id, 'channelNo':channelNo}
  140. res2 = requests.post(ctrl_url,data=data)
  141. return True
  142. @kedong_deco(login_required=False)
  143. def see_camera_account(request):
  144. """
  145. 查看当前绑定的萤石云账号信息\按业务员名字搜索\萤石云账号搜索
  146. 参数:
  147. account 非必传(str) 按萤石云账号名字搜索
  148. salesman 非必传(str) 按业务员名字搜索
  149. 说明:两个参数都不传为所有数据,不进行筛选操作
  150. 返回值:
  151. {
  152. "errorCode": 0,
  153. "message": "",
  154. "formError": {},
  155. "data": [
  156. {
  157. "id": 1, 萤石云账号id
  158. "account": "hnyf" 萤石云名称
  159. }
  160. ],
  161. "params": {}
  162. }
  163. """
  164. account = request.POST.get("account")
  165. salesman = request.POST.get("salesman")
  166. camera_query = MongoCameraAccount.objects.all().order_by("-id")
  167. if account:
  168. camera_query = camera_query.filter(account__icontains=account)
  169. if salesman:
  170. camera_query = camera_query.filter(salesman__icontains=salesman)
  171. data = [{'id':i.id,'account':i.account} for i in camera_query]
  172. return data
  173. @kedong_deco(login_required=True)
  174. def add_camera_account(request):
  175. """
  176. 添加萤石云账号
  177. 管理员可操作
  178. 参数:
  179. account 必传(str) 萤石云账号
  180. salesman 必传(str) 萤石云账号所相关的业务员名称
  181. app_token 必传(str) 萤石云账号 token
  182. app_key 必传(str) 萤石云账号 appkey
  183. app_secret 必传(str) 萤石云账号 appsecret
  184. 2022-08-19 08:54 csx
  185. 增加监控账户区分,在不影响原来的功能上进行修改,增加大华乐橙云账号添加
  186. account_type 非必传(number) 监控设备类型 0代表海康 1代表大华,默认是0
  187. """
  188. account = request.POST.get("account")
  189. salesman = request.POST.get("salesman")
  190. token = request.POST.get("app_token")
  191. app_key = request.POST.get("app_key")
  192. app_secret = request.POST.get("app_secret")
  193. account_type = request.POST.get("account_type","0")
  194. if account_type not in ("0","1"):
  195. raise PortError("","无法识别此监控账号类型")
  196. if not all([account,salesman,token,app_key,app_secret]):
  197. raise PortError("","请把参数填写完整")
  198. now_time = int(time.time())
  199. camera_query = MongoCameraAccount.objects.filter(app_key=app_key,account_type=account_type).first()
  200. if camera_query:
  201. raise PortError("","此appkey已存在,请勿重复添加")
  202. try:
  203. MongoCameraAccount.objects.create(account=account,salesman=salesman,token=token,addtime=now_time,uptime=now_time,
  204. app_key=app_key,app_secret=app_secret,account_type=account_type)
  205. except:
  206. raise PortError("","添加萤石账号失败")
  207. return True
  208. @transaction.atomic
  209. @kedong_deco(login_required=True)
  210. def add_camera(request):
  211. """
  212. 添加监控设备接口:
  213. 参数:
  214. device_id 必传 (string) 监控设备的序列号
  215. camera_channel 必传 (string) 监控通道号
  216. camera_playback 必传 (string) 是否支持回放功能,0不支持 1支持
  217. 新加参数
  218. account_id 必传 (string) 萤石云账号id
  219. 2022-08-19 08:54 csx
  220. 增加监控账户区分,在不影响原来的功能上进行修改,增加大华乐橙云监控绑定
  221. 返回值:
  222. {
  223. "data": null,
  224. "errorCode": 0,
  225. "message": ,
  226. "formError": {}
  227. }
  228. """
  229. device_id = request.POST.get('device_id')
  230. camera_channel = request.POST.get("camera_channel","0")
  231. camera_playback = request.POST.get("camera_playback","0")
  232. account_id = request.POST.get("account_id",1)
  233. if not account_id.isdigit():
  234. raise PortError("account_id","无效参数")
  235. if not device_id:
  236. raise PortError("device_id","未传设备号")
  237. if not camera_channel.isdigit():
  238. raise PortError("camera_channel","无效参数")
  239. if camera_playback not in ("0","1"):
  240. raise PortError("camera_playback","参数超出范围")
  241. now_time = int(time.time())
  242. camera_query = MongoCameraAccount.objects.filter(id=int(account_id)).first()
  243. if not camera_query:
  244. raise PortError("","未找到此账号")
  245. device_ids = device_id + "-" + camera_channel
  246. # if MongoCameraData.objects.filter(device_id=device_id).exists() or MongoDevice.objects.filter(device_id=device_id).exists():
  247. # raise PortError("","设备已存在,请勿重复添加")
  248. # 使用的是大华乐橙云账号监控接入,监控通道号大华的从0开始
  249. coverUrl = ""
  250. if camera_query.account_type == 1:
  251. appId = camera_query.app_key
  252. appSecret = camera_query.app_secret
  253. device_live_data = bindDeviceLive(appId, appSecret, device_id,camera_channel)
  254. code = device_live_data["result"]["code"]
  255. if code == "0":
  256. live_path = device_live_data["result"]["data"]["streams"][0]["hls"]
  257. elif code == "LV1001":
  258. # 如直播地址已存在,则需要查询直播地址列表
  259. live_data = getLive(appId, appSecret, device_id, camera_channel)
  260. coverUrl = live_data["result"]["data"]["streams"][0]["coverUrl"]
  261. if live_data["result"]["code"] == "0":
  262. try:
  263. live_path = live_data["result"]["data"]["streams"][0]["hls"]
  264. except:
  265. raise PortError("","获取直播地址失败")
  266. else:
  267. raise PortError("",live_data)
  268. else:
  269. msg = device_live_data["result"]["msg"]
  270. raise PortError("", msg)
  271. device_info = {
  272. "hls": live_path,
  273. "hlsHd": live_path,
  274. "rtmp": live_path,
  275. "rtmpHd": live_path
  276. }
  277. else:
  278. accessToken = camera_query.token
  279. url = config_dict.get("camera").get("ys_open")
  280. data = {"accessToken":accessToken,"source":"%s:%s"%(device_id,str(camera_channel))}
  281. res = requests.post(url,data=data)
  282. if ast.literal_eval(res.text)["code"] == "200":
  283. url_1 = config_dict.get("camera").get("ys_get")
  284. res_1 = requests.post(url_1,data=data)
  285. try:
  286. addr = ast.literal_eval(res_1.text)["data"][0]
  287. device_info = {
  288. "hls": addr["hls"],
  289. "hlsHd": addr["hlsHd"],
  290. "rtmp": addr["rtmp"],
  291. "rtmpHd": addr["rtmpHd"]
  292. }
  293. except Exception as e:
  294. raise PortError("device_id", "解析结果异常")
  295. else:
  296. raise PortError("","Token过期,设备激活失败")
  297. try:
  298. MongoDevice.objects.create(device_id=device_ids,device_type_id=6,addtime=now_time,device_code=1,uptime=now_time, jk_live_img=coverUrl)
  299. MongoCameraData.objects.create(device_id=device_ids,device_info=device_info,addtime=now_time,camera_playback=camera_playback,account_id=account_id)
  300. except Exception as e:
  301. print(e)
  302. raise PortError(" ", "添加设备失败")
  303. return True
  304. @kedong_deco(login_required=True)
  305. def camera_config(request):
  306. """
  307. 监控设置
  308. 参数:
  309. device_name 必传(str) 设备名称
  310. off_on 必传(str) 设备开关 off 关 on 开
  311. start_time 非必传(str) 开始时间 为开时 必传
  312. end_time 非必传(str) 结束时间 为开时 必传
  313. device_id 必传(str) 设备号
  314. """
  315. device_id = request.POST.get("device_id")
  316. off_on = request.POST.get("off_on","")
  317. start_time = request.POST.get("start_time","")
  318. end_time = request.POST.get("end_time","")
  319. device_ids = request.POST.get("device_id")
  320. device_name = request.POST.get("device_name")
  321. redis_pool = RedisPool().get_redis_pool(settings.redis_db["captcha"])
  322. try:
  323. device_query = MongoDevice.objects.get(device_id=device_ids)
  324. except:
  325. raise PortError("","未找出此设备")
  326. account_id = MongoCameraData.objects.filter(device_id=device_ids).first()
  327. if not account_id:
  328. raise PortError("","未找到此设备")
  329. camera_query = MongoCameraAccount.objects.filter(id=int(account_id.account_id)).first()
  330. if not camera_query:
  331. raise PortError("","未找到此账号")
  332. channelNo = "1"
  333. if device_ids.find("-") != -1:
  334. channelNo = device_ids.split("-")[1]
  335. device_id = device_ids.split("-")[0]
  336. else:
  337. device_id = device_ids
  338. if camera_query.account_type == 1:
  339. appId = camera_query.app_key
  340. appSecret = camera_query.app_secret
  341. live_token = redis_pool.get(device_ids)
  342. if not live_token:
  343. live_data = getLive(appId, appSecret, device_id, channelNo)
  344. if live_data["result"]["code"] == "0":
  345. try:
  346. live_token = live_data["result"]["data"]["streams"][0]["liveToken"]
  347. redis_pool.set(device_ids,live_token,60*60*23)
  348. except:
  349. raise PortError("","获取liveToken失败")
  350. else:
  351. raise PortError("",live_data)
  352. else:
  353. raise PortError("","其它设备没有此功能")
  354. if off_on == "on":
  355. if not start_time and not end_time:
  356. status = modify_live_time(appId,appSecret,live_token,start_time,end_time,"always")
  357. else:
  358. # 时间内开启直播
  359. status = modify_live_time(appId,appSecret,live_token,start_time,end_time)
  360. elif off_on == "off":
  361. status = off_on_live(appId,appSecret,live_token,off_on)
  362. else:
  363. raise PortError("","参数超出范围")
  364. if status["result"]["code"] == "0":
  365. device_query.device_name = device_name
  366. device_query.save()
  367. config = off_on + "-" + start_time + "-" + end_time
  368. redis_pool.set(device_ids+"config",config)
  369. return True
  370. else:
  371. return status
  372. @kedong_deco(login_required=True)
  373. def camera_takephoto(request):
  374. # 监控拍照接口
  375. device_id = request.POST.get("device_id")
  376. if not device_id:
  377. raise PortError("","设备号未传")
  378. try:
  379. d_id = MongoDevice.objects.get(device_id=device_id).id
  380. except:
  381. raise PortError("","未找出此设备")
  382. account_id = MongoCameraData.objects.filter(device_id=device_id).first()
  383. if not account_id:
  384. raise PortError("","未找到此设备")
  385. camera_query = MongoCameraAccount.objects.filter(id=int(account_id.account_id)).first()
  386. if not camera_query:
  387. raise PortError("","未找到此账号")
  388. channelNo = "0"
  389. if device_id.find("-") != -1:
  390. channelNo = device_id.split("-")[1]
  391. device_id = device_id.split("-")[0]
  392. else:
  393. device_id = device_id
  394. appId = camera_query.app_key
  395. appSecret = camera_query.app_secret
  396. snap_url = setDeviceSnap(appId, appSecret, device_id, channelNo)
  397. print(snap_url)
  398. # snap_url = "https://lechangecloud.oss-cn-hangzhou.aliyuncs.com/lechange/snappic/8H09715PHA657EC_img/Alarm/0/9d9913c5112c4587a391b6c454110c5a.jpg?Expires=1690882790&OSSAccessKeyId=LTAIP4igXeEjYBoG&Signature=RK97RSfcLjyA84Fv8aFOtA%2BvGao%3D"
  399. # snap_url = "https://lechangecloud.oss-cn-hangzhou.aliyuncs.com/lechange/snappic/8H09715PHA24E37_img/Alarm/0/ab85f10f33a34f068dc55a4a64e51584.jpg?Expires=1690883565&OSSAccessKeyId=LTAIP4igXeEjYBoG&Signature=%2FP1Bxksx0lagn24gkwaXWcS9Dno%3D"
  400. time.sleep(5)
  401. if snap_url:
  402. # 图片保存位置
  403. config = settings.CONFIG
  404. save_path = "/jiankong/" + device_id + "/" + time.strftime("%Y%m%d", time.localtime())
  405. camera_path = config.get("media") + save_path
  406. os.makedirs(camera_path) if not os.path.exists(camera_path) else None
  407. stamp = int(time.time())
  408. unique_id = uuid.uuid4()
  409. combined_id = str(stamp) + "-" + str(unique_id)
  410. camera_photos = combined_id + ".jpg"
  411. img_path = os.path.join(camera_path, camera_photos)
  412. # 下载图片
  413. img_query = requests.get(snap_url, timeout=5)
  414. if img_query.status_code == 200:
  415. img = Image.open(BytesIO(img_query.content))
  416. img.save(img_path)
  417. camera_obj = MongoCameraPhoto.objects.create(
  418. device_id=d_id,
  419. addr=f"/media{save_path}/{camera_photos}",
  420. photo_status=1,
  421. addtime=int(time.time())
  422. )
  423. if camera_obj:
  424. return {"addr":camera_photos}
  425. else:
  426. raise PortError("","保存图片失败,稍后重试")
  427. else:
  428. raise PortError("","下载图片失败,稍后重试")
  429. else:
  430. raise PortError("","拍照失败,稍后重试")
  431. @kedong_deco(login_required=True)
  432. def camera_photo(request):
  433. # 拍照列表
  434. request_data = request.POST
  435. device_id = request_data.get("device_id")
  436. start_time = request_data.get("start_time","")
  437. end_time = request_data.get("end_time","")
  438. page_num = int(request_data.get("page")) if request_data.get("page") else 1
  439. page_size = int(request_data.get("pagesize")) if request_data.get("pagesize") else 10
  440. queryset = MongoCameraPhoto.objects.filter(device_id=device_id).order_by("-addtime")
  441. if start_time and end_time:
  442. queryset = queryset.filter(addtime__gte=start_time, addtime__lte=end_time)
  443. paginator = Paginator(queryset, page_size)
  444. page_obj = paginator.get_page(page_num)
  445. serializers = MongoCameraPhotoSerializers(page_obj, many=True)
  446. return {"data": serializers.data, "counts": queryset.count()}
  447. @kedong_deco(login_required=True)
  448. def get_camera_dh_tokens(request):
  449. """
  450. 获取大华相机token
  451. 参数:
  452. device_id 必传(string) 设备号
  453. """
  454. device_id = request.POST.get("device_id")
  455. if not device_id:
  456. raise PortError("","参数缺失")
  457. camera_query = MongoCameraData.objects.filter(device_id=device_id).first()
  458. if not camera_query:
  459. raise PortError("","未找到此设备")
  460. camera_account_query = MongoCameraAccount.objects.filter(id=camera_query.account_id).first()
  461. if not camera_account_query:
  462. raise PortError("","此设备未绑定监控账号")
  463. if camera_account_query.account_type == 0:
  464. raise PortError('', '海康监控暂不支持获取token')
  465. if device_id.find("-") != -1:
  466. channelNo = device_id.split("-")[1]
  467. device_id = device_id.split("-")[0]
  468. appId = camera_account_query.app_key
  469. appSecret = camera_account_query.app_secret
  470. like_token_data = getKitToken(appId, appSecret,device_id,channelNo)
  471. return like_token_data
  472. @kedong_deco(login_required=True)
  473. def get_camera_dh_token(request):
  474. """
  475. 获取大华相机token
  476. 参数:
  477. device_id 必传(string) 设备号
  478. """
  479. device_id = request.POST.get("device_id")
  480. if not device_id:
  481. raise PortError("","参数缺失")
  482. camera_query = MongoCameraData.objects.filter(device_id=device_id).first()
  483. if not camera_query:
  484. raise PortError("","未找到此设备")
  485. camera_account_query = MongoCameraAccount.objects.filter(id=camera_query.account_id).first()
  486. if not camera_account_query:
  487. raise PortError("","此设备未绑定监控账号")
  488. if camera_account_query.account_type == 0:
  489. raise PortError('', '海康监控暂不支持获取token')
  490. if device_id.find("-") != -1:
  491. channelNo = device_id.split("-")[1]
  492. device_id = device_id.split("-")[0]
  493. appId = camera_account_query.app_key
  494. appSecret = camera_account_query.app_secret
  495. like_token_data = getRecord(appId, appSecret,device_id,channelNo)
  496. return like_token_data