import re import requests import time import ast import os import datetime import uuid from PIL import Image from io import BytesIO from django.conf import settings from django.db.models import Count from django.core.paginator import Paginator from django.db import transaction from smartfarming.api.views.forecast.all_dict import insect_dict, attract_discern from smartfarming.models.sim_card import MongoMsg_Conf from smartfarming.models.device import MongoDevice from smartfarming.models.camera import MongoCameraPhoto, MongoCameraData, MongoCameraAccount from smartfarming.serializers.device_serializers import DeviceSerializers from smartfarming.utils import bindDeviceLive, getLive, controlMove, modify_live_time, off_on_live, setDeviceSnap, getKitToken, getRecord from kedong.tools import RedisPool from kedong.decoration import kedong_deco, PortError from smartfarming.api.views.camera.cameraserializers import ( MongoCameraPhotoSerializers, MongoDeviceCameraSerializers ) config_dict = settings.CONFIG @kedong_deco(login_required=True) def list_camera(request): # 获取监控设备列表 post_info = request.POST device_id = post_info.get('device_id') page_num = int(post_info.get('page', 1)) page_size = int(post_info.get('page_size', 10)) queryset = MongoDevice.objects.filter(device_type_id=6).order_by("-uptime") if device_id: queryset = queryset.filter(device_id=device_id) paginator = Paginator(queryset, page_size) page_obj = paginator.get_page(page_num) serializers = MongoDeviceCameraSerializers(page_obj, many=True) datas = {"data": serializers.data, "counts": queryset.count()} return datas @kedong_deco(login_required=True) def addr_camera_list(request): """ 获取监控设备播放地址 参数: device_id 必传 (string) 监控设备的序列号 返回值: { "data": { "hls": "http://test.ys7.com:66/openlive/b475942b03544a5aa35b651670d8712c.m3u8", HLS流畅直播地址 "hlsHd": "http://test.ys7.com:66/openlive/b475942b03544a5aa35b651670d8712c.hd.m3u8", HLS高清直播地址 "rtmp": "rtmp://10.82.0.190:1935/openlive/b475942b03544a5aa35b651670d8712c", RTMP流畅直播地址 "rtmpHd": "rtmp://10.82.0.190:1935/openlive/b475942b03544a5aa35b651670d8712c.hd" RTMP高清直播地址 } "errorCode": 0, "message": "", "formError": {} } """ try: if 'HTTP_X_FORWARDED_FOR' in request.META: ip = request.META['HTTP_X_FORWARDED_FOR'] else: ip = request.META['HTTP_X_REAL_IP'] except Exception as KeyError: ip = request.META['REMOTE_ADDR'] device_id = request.POST.get('device_id') try: addr = MongoCameraData.objects.get(device_id=device_id).device_info except: addr = {} return addr @kedong_deco(login_required=True) def ctrl_camera(request): """ 控制监控设备转动 : 参数: device_id 必传 (string) 监控设备的序列号 ctrl 必传 (string) 操作指令 move 控制球机转动 stop 停止球机转动 movenum ctrl=move时必传(string) 0-上,1-下,2-左,3-右,8-放大,9-缩小 返回值: { "data": success, success成功 default失败 "errorCode": 0, "message": "", "formError": {} } """ device_id = request.POST.get('device_id') ctrl = request.POST.get('ctrl') account_id = MongoCameraData.objects.filter(device_id=device_id).first() if not account_id: raise PortError("","未找到此设备") camera_query = MongoCameraAccount.objects.filter(id=int(account_id.account_id)).first() if not camera_query: raise PortError("","未找到此账号") channelNo = "1" if device_id.find("-") != -1: channelNo = device_id.split("-")[1] device_id = device_id.split("-")[0] # 操作命令:0-上,1-下,2-左,3-右,4-左上,5-左下,6-右上,7-右下,8-放大,9-缩小,10-近焦距,11-远焦距 if ctrl == "move": dire = request.POST.get('movenum') # 增加大华相机操作功能 if camera_query.account_type == 1: if dire not in ("0","1","2","3","8","9"): raise PortError("movenum","暂不支持其它指令") appId = camera_query.app_key appSecret = camera_query.app_secret result = controlMove(appId,appSecret,device_id,dire,channelNo) code = result.get("result").get("code") if code == "0": return True else: return {"errorCode": 2, "msg": result.get("result").get("msg")} else: accessToken = camera_query.token ctrl_url = 'https://open.ys7.com/api/lapp/device/ptz/start' speed = '1' data = {'accessToken':accessToken, 'deviceSerial':device_id, 'channelNo':channelNo, 'speed':speed, 'direction':dire} res1 = requests.post(ctrl_url,data=data) elif ctrl == "stop": time.sleep(0.4) # 增加大华相机操作功能 if camera_query.account_type == 1: dire = "10" appId = camera_query.app_key appSecret = camera_query.app_secret result = controlMove(appId,appSecret,device_id,dire,channelNo) code = result.get("result").get("code") if code == "0": return True else: return {"errorCode": 2, "msg": result.get("result").get("msg")} else: accessToken = camera_query.token ctrl_url = 'https://open.ys7.com/api/lapp/device/ptz/stop' data = {'accessToken':accessToken, 'deviceSerial':device_id, 'channelNo':channelNo} res2 = requests.post(ctrl_url,data=data) return True @kedong_deco(login_required=False) def see_camera_account(request): """ 查看当前绑定的萤石云账号信息\按业务员名字搜索\萤石云账号搜索 参数: account 非必传(str) 按萤石云账号名字搜索 salesman 非必传(str) 按业务员名字搜索 说明:两个参数都不传为所有数据,不进行筛选操作 返回值: { "errorCode": 0, "message": "", "formError": {}, "data": [ { "id": 1, 萤石云账号id "account": "hnyf" 萤石云名称 } ], "params": {} } """ account = request.POST.get("account") salesman = request.POST.get("salesman") camera_query = MongoCameraAccount.objects.all().order_by("-id") if account: camera_query = camera_query.filter(account__icontains=account) if salesman: camera_query = camera_query.filter(salesman__icontains=salesman) data = [{'id':i.id,'account':i.account} for i in camera_query] return data @kedong_deco(login_required=True) def add_camera_account(request): """ 添加萤石云账号 管理员可操作 参数: account 必传(str) 萤石云账号 salesman 必传(str) 萤石云账号所相关的业务员名称 app_token 必传(str) 萤石云账号 token app_key 必传(str) 萤石云账号 appkey app_secret 必传(str) 萤石云账号 appsecret 2022-08-19 08:54 csx 增加监控账户区分,在不影响原来的功能上进行修改,增加大华乐橙云账号添加 account_type 非必传(number) 监控设备类型 0代表海康 1代表大华,默认是0 """ account = request.POST.get("account") salesman = request.POST.get("salesman") token = request.POST.get("app_token") app_key = request.POST.get("app_key") app_secret = request.POST.get("app_secret") account_type = request.POST.get("account_type","0") if account_type not in ("0","1"): raise PortError("","无法识别此监控账号类型") if not all([account,salesman,token,app_key,app_secret]): raise PortError("","请把参数填写完整") now_time = int(time.time()) camera_query = MongoCameraAccount.objects.filter(app_key=app_key,account_type=account_type).first() if camera_query: raise PortError("","此appkey已存在,请勿重复添加") try: MongoCameraAccount.objects.create(account=account,salesman=salesman,token=token,addtime=now_time,uptime=now_time, app_key=app_key,app_secret=app_secret,account_type=account_type) except: raise PortError("","添加萤石账号失败") return True @transaction.atomic @kedong_deco(login_required=True) def add_camera(request): """ 添加监控设备接口: 参数: device_id 必传 (string) 监控设备的序列号 camera_channel 必传 (string) 监控通道号 camera_playback 必传 (string) 是否支持回放功能,0不支持 1支持 新加参数 account_id 必传 (string) 萤石云账号id 2022-08-19 08:54 csx 增加监控账户区分,在不影响原来的功能上进行修改,增加大华乐橙云监控绑定 返回值: { "data": null, "errorCode": 0, "message": , "formError": {} } """ device_id = request.POST.get('device_id') camera_channel = request.POST.get("camera_channel","0") camera_playback = request.POST.get("camera_playback","0") account_id = request.POST.get("account_id",1) if not account_id.isdigit(): raise PortError("account_id","无效参数") if not device_id: raise PortError("device_id","未传设备号") if not camera_channel.isdigit(): raise PortError("camera_channel","无效参数") if camera_playback not in ("0","1"): raise PortError("camera_playback","参数超出范围") now_time = int(time.time()) camera_query = MongoCameraAccount.objects.filter(id=int(account_id)).first() if not camera_query: raise PortError("","未找到此账号") device_ids = device_id + "-" + camera_channel # if MongoCameraData.objects.filter(device_id=device_id).exists() or MongoDevice.objects.filter(device_id=device_id).exists(): # raise PortError("","设备已存在,请勿重复添加") # 使用的是大华乐橙云账号监控接入,监控通道号大华的从0开始 coverUrl = "" if camera_query.account_type == 1: appId = camera_query.app_key appSecret = camera_query.app_secret device_live_data = bindDeviceLive(appId, appSecret, device_id,camera_channel) code = device_live_data["result"]["code"] if code == "0": live_path = device_live_data["result"]["data"]["streams"][0]["hls"] elif code == "LV1001": # 如直播地址已存在,则需要查询直播地址列表 live_data = getLive(appId, appSecret, device_id, camera_channel) coverUrl = live_data["result"]["data"]["streams"][0]["coverUrl"] if live_data["result"]["code"] == "0": try: live_path = live_data["result"]["data"]["streams"][0]["hls"] except: raise PortError("","获取直播地址失败") else: raise PortError("",live_data) else: msg = device_live_data["result"]["msg"] raise PortError("", msg) device_info = { "hls": live_path, "hlsHd": live_path, "rtmp": live_path, "rtmpHd": live_path } else: accessToken = camera_query.token url = config_dict.get("camera").get("ys_open") data = {"accessToken":accessToken,"source":"%s:%s"%(device_id,str(camera_channel))} res = requests.post(url,data=data) if ast.literal_eval(res.text)["code"] == "200": url_1 = config_dict.get("camera").get("ys_get") res_1 = requests.post(url_1,data=data) try: addr = ast.literal_eval(res_1.text)["data"][0] device_info = { "hls": addr["hls"], "hlsHd": addr["hlsHd"], "rtmp": addr["rtmp"], "rtmpHd": addr["rtmpHd"] } except Exception as e: raise PortError("device_id", "解析结果异常") else: raise PortError("","Token过期,设备激活失败") try: MongoDevice.objects.create(device_id=device_ids,device_type_id=6,addtime=now_time,device_code=1,uptime=now_time, jk_live_img=coverUrl) MongoCameraData.objects.create(device_id=device_ids,device_info=device_info,addtime=now_time,camera_playback=camera_playback,account_id=account_id) except Exception as e: print(e) raise PortError(" ", "添加设备失败") return True @kedong_deco(login_required=True) def camera_config(request): """ 监控设置 参数: device_name 必传(str) 设备名称 off_on 必传(str) 设备开关 off 关 on 开 start_time 非必传(str) 开始时间 为开时 必传 end_time 非必传(str) 结束时间 为开时 必传 device_id 必传(str) 设备号 """ device_id = request.POST.get("device_id") off_on = request.POST.get("off_on","") start_time = request.POST.get("start_time","") end_time = request.POST.get("end_time","") device_ids = request.POST.get("device_id") device_name = request.POST.get("device_name") redis_pool = RedisPool().get_redis_pool(settings.redis_db["captcha"]) try: device_query = MongoDevice.objects.get(device_id=device_ids) except: raise PortError("","未找出此设备") account_id = MongoCameraData.objects.filter(device_id=device_ids).first() if not account_id: raise PortError("","未找到此设备") camera_query = MongoCameraAccount.objects.filter(id=int(account_id.account_id)).first() if not camera_query: raise PortError("","未找到此账号") channelNo = "1" if device_ids.find("-") != -1: channelNo = device_ids.split("-")[1] device_id = device_ids.split("-")[0] else: device_id = device_ids if camera_query.account_type == 1: appId = camera_query.app_key appSecret = camera_query.app_secret live_token = redis_pool.get(device_ids) if not live_token: live_data = getLive(appId, appSecret, device_id, channelNo) if live_data["result"]["code"] == "0": try: live_token = live_data["result"]["data"]["streams"][0]["liveToken"] redis_pool.set(device_ids,live_token,60*60*23) except: raise PortError("","获取liveToken失败") else: raise PortError("",live_data) else: raise PortError("","其它设备没有此功能") if off_on == "on": if not start_time and not end_time: status = modify_live_time(appId,appSecret,live_token,start_time,end_time,"always") else: # 时间内开启直播 status = modify_live_time(appId,appSecret,live_token,start_time,end_time) elif off_on == "off": status = off_on_live(appId,appSecret,live_token,off_on) else: raise PortError("","参数超出范围") if status["result"]["code"] == "0": device_query.device_name = device_name device_query.save() config = off_on + "-" + start_time + "-" + end_time redis_pool.set(device_ids+"config",config) return True else: return status @kedong_deco(login_required=True) def camera_takephoto(request): # 监控拍照接口 device_id = request.POST.get("device_id") if not device_id: raise PortError("","设备号未传") try: d_id = MongoDevice.objects.get(device_id=device_id).id except: raise PortError("","未找出此设备") account_id = MongoCameraData.objects.filter(device_id=device_id).first() if not account_id: raise PortError("","未找到此设备") camera_query = MongoCameraAccount.objects.filter(id=int(account_id.account_id)).first() if not camera_query: raise PortError("","未找到此账号") channelNo = "0" if device_id.find("-") != -1: channelNo = device_id.split("-")[1] device_id = device_id.split("-")[0] else: device_id = device_id appId = camera_query.app_key appSecret = camera_query.app_secret snap_url = setDeviceSnap(appId, appSecret, device_id, channelNo) print(snap_url) # 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" # snap_url = "https://lechangecloud.oss-cn-hangzhou.aliyuncs.com/lechange/snappic/8H09715PHA24E37_img/Alarm/0/ab85f10f33a34f068dc55a4a64e51584.jpg?Expires=1690883565&OSSAccessKeyId=LTAIP4igXeEjYBoG&Signature=%2FP1Bxksx0lagn24gkwaXWcS9Dno%3D" time.sleep(5) if snap_url: # 图片保存位置 config = settings.CONFIG save_path = "/jiankong/" + device_id + "/" + time.strftime("%Y%m%d", time.localtime()) camera_path = config.get("media") + save_path os.makedirs(camera_path) if not os.path.exists(camera_path) else None stamp = int(time.time()) unique_id = uuid.uuid4() combined_id = str(stamp) + "-" + str(unique_id) camera_photos = combined_id + ".jpg" img_path = os.path.join(camera_path, camera_photos) # 下载图片 img_query = requests.get(snap_url, timeout=5) if img_query.status_code == 200: img = Image.open(BytesIO(img_query.content)) img.save(img_path) camera_obj = MongoCameraPhoto.objects.create( device_id=d_id, addr=f"/media{save_path}/{camera_photos}", photo_status=1, addtime=int(time.time()) ) if camera_obj: return {"addr":camera_photos} else: raise PortError("","保存图片失败,稍后重试") else: raise PortError("","下载图片失败,稍后重试") else: raise PortError("","拍照失败,稍后重试") @kedong_deco(login_required=True) def camera_photo(request): # 拍照列表 request_data = request.POST device_id = request_data.get("device_id") start_time = request_data.get("start_time","") end_time = request_data.get("end_time","") page_num = int(request_data.get("page")) if request_data.get("page") else 1 page_size = int(request_data.get("pagesize")) if request_data.get("pagesize") else 10 queryset = MongoCameraPhoto.objects.filter(device_id=device_id).order_by("-addtime") if start_time and end_time: queryset = queryset.filter(addtime__gte=start_time, addtime__lte=end_time) paginator = Paginator(queryset, page_size) page_obj = paginator.get_page(page_num) serializers = MongoCameraPhotoSerializers(page_obj, many=True) return {"data": serializers.data, "counts": queryset.count()} @kedong_deco(login_required=True) def get_camera_dh_tokens(request): """ 获取大华相机token 参数: device_id 必传(string) 设备号 """ device_id = request.POST.get("device_id") if not device_id: raise PortError("","参数缺失") camera_query = MongoCameraData.objects.filter(device_id=device_id).first() if not camera_query: raise PortError("","未找到此设备") camera_account_query = MongoCameraAccount.objects.filter(id=camera_query.account_id).first() if not camera_account_query: raise PortError("","此设备未绑定监控账号") if camera_account_query.account_type == 0: raise PortError('', '海康监控暂不支持获取token') if device_id.find("-") != -1: channelNo = device_id.split("-")[1] device_id = device_id.split("-")[0] appId = camera_account_query.app_key appSecret = camera_account_query.app_secret like_token_data = getKitToken(appId, appSecret,device_id,channelNo) return like_token_data @kedong_deco(login_required=True) def get_camera_dh_token(request): """ 获取大华相机token 参数: device_id 必传(string) 设备号 """ device_id = request.POST.get("device_id") if not device_id: raise PortError("","参数缺失") camera_query = MongoCameraData.objects.filter(device_id=device_id).first() if not camera_query: raise PortError("","未找到此设备") camera_account_query = MongoCameraAccount.objects.filter(id=camera_query.account_id).first() if not camera_account_query: raise PortError("","此设备未绑定监控账号") if camera_account_query.account_type == 0: raise PortError('', '海康监控暂不支持获取token') if device_id.find("-") != -1: channelNo = device_id.split("-")[1] device_id = device_id.split("-")[0] appId = camera_account_query.app_key appSecret = camera_account_query.app_secret like_token_data = getRecord(appId, appSecret,device_id,channelNo) return like_token_data