factory/apps/third/dahua.py

312 lines
10 KiB
Python

import logging
import json
import time
from threading import Thread
import traceback
import uuid
import requests
from requests.exceptions import RequestException
from django.conf import settings
from rest_framework.exceptions import APIException, ParseError
from apps.third.errors import DH_REQUEST_ERROR
from apps.third.models import Tlog
from apps.utils.my_rsa import encrypt_data
from apps.utils.tools import convert_to_base64, print_roundtrip
from django.utils.timezone import now
from apps.third.tapis import dhapis
from apps.utils.tools import singleton
from django.core.cache import cache
requests.packages.urllib3.disable_warnings()
myLogger = logging.getLogger('log')
@singleton
class DhClient:
"""
大华
"""
def __init__(self):
self.dahua_enabled = getattr(settings, 'DAHUA_ENABLED', False)
if self.dahua_enabled:
self.dahua_enabled = True
self.client_id = settings.DAHUA_CLIENTID
self.client_secret = settings.DAHUA_SECRET
self.headers = {"Connection": "close"}
self.isGetingToken = False
self.log = {}
# self._get_token()
def _get_token(self):
self.isGetingToken = True
params = {
'grant_type': 'client_credentials',
'client_id': self.client_id,
'client_secret': self.client_secret
}
is_ok, res = self.request(
**dhapis['token_login'], params=params, raise_exception=False, timeout=10)
if is_ok == 'success':
cache.set('dh_token', res['access_token'], timeout=None)
self.isGetingToken = False
def request(self, url: str, method: str, params=dict(), json=dict(), timeout=120,
file_path_rela=None, raise_exception=True):
if not self.dahua_enabled:
raise ParseError('大华对接未启用')
self.headers['Authorization'] = 'bearer ' + cache.get('dh_token', '')
self.headers['User-Id'] = '1'
self.log = {"requested_at": now(), "id": uuid.uuid4(), "path": url, "method": method,
"params": params, "body": json, "target": "dahua", "result": 10, "headers": self.headers}
files = None
if file_path_rela: # 相对路径
files = {'file': open(settings.BASE_DIR + file_path_rela, 'rb')}
if params:
url = url.format(**params)
self.log.update({"path": url})
try:
r = getattr(requests, method)('{}{}'.format(settings.DAHUA_BASE_URL, url),
headers=self.headers, params=params, json=json,
timeout=timeout, files=files, verify=False)
# if settings.DEBUG:
# print_roundtrip(r)
ret = r.text
if 300 > r.status_code >= 200:
ret = r.json()
if ret['code'] not in ['0', '100', '00000', '1000', 0, 100, 1000]:
detail = '大华错误:' + \
'{}|{}{}{}'.format(str(ret['code']), ret.get('errMsg', ''),
ret.get('desc', ''), str(ret.get('data', '')))
err_detail = dict(
detail=detail, code='dh_'+str(ret['code']))
self.handle_log(result='fail', response=ret)
if raise_exception:
raise ParseError(**err_detail)
return 'fail', err_detail
# self.handle_log(result='success', response=ret) # 成功的日志就不记录了
return 'success', ret['data'] if 'data' in ret else None
else:
self.handle_log(result='error', response=ret)
except RequestException:
self.handle_log(result='error', errors=traceback.format_exc())
if raise_exception:
raise APIException(**DH_REQUEST_ERROR)
return 'error', DH_REQUEST_ERROR
def _get_response_ms(self):
"""
Get the duration of the request response cycle is milliseconds.
In case of negative duration 0 is returned.
"""
response_timedelta = now() - self.log["requested_at"]
response_ms = int(response_timedelta.total_seconds() * 1000)
return max(response_ms, 0)
def handle_log(self, result, response=None, errors=None):
self.log.update({
"result": result,
"response": response,
"response_ms": self._get_response_ms(),
"errors": errors
})
Tlog(**self.log).save()
def get_full_pic(self, path: str):
"""返回完整访问地址
"""
return '{}/evo-apigw/evo-oss/{}?token={}'.format(settings.DAHUA_BASE_URL, path, cache.get('dh_token', ''))
def snap(self, code: str, raise_exception:bool):
"""摄像头实时截图
Args:
code (str): 视频通道编号
返回完整访问地址
"""
json_data = {
"deviceCode": "1000093",
"operation": "generalJsonTransport"
}
if '$' in code:
d_code_list = code.split('$')
d_code = d_code_list[0]
num = d_code_list[-1]
json_data['deviceCode'] = d_code
json_data['params'] = '{\"method\":\"dev.snap\",\"id\":123,\"params\":{\"DevID\":\"' + \
str(d_code) + '\",\"DevChannel\":' + str(num) + \
',\"PicNum\":1,\"SnapType\":1,\"CmdSrc\":0}}'
is_ok, res = self.request(**dhapis['dev_snap'], json=json_data, raise_exception=raise_exception)
if is_ok == 'success':
res = json.loads(res)
return self.get_full_pic(res['params']['PicInfo'])
return None
def get_password_token(self):
_, res = self.request(**dhapis['oauth_key'])
e_pwd = encrypt_data(settings.DAHUA_PASSWORD, res['publicKey'])
res['public_key'] = res['publicKey']
res['password'] = e_pwd
res.update({
"grant_type": "password",
"username": settings.DAHUA_USERNAME,
"client_id": settings.DAHUA_CLIENTID,
"client_secret": settings.DAHUA_SECRET,
})
_, res2 = self.request(**dhapis['oauth_token'], json=res)
return res2
def face_search(self, path: str):
"""人像库检索
Args:
path (str): 图片地址
返回识别结果
"""
base64img = convert_to_base64(path)
json_data = {
"base64Img": base64img,
"devType": 1,
"deviceCodes": ["1000038"],
"groupIds": ["100001"],
"searchGroupType": 2,
"threshold": "80"
}
_, res = self.request(**dhapis['face_search'], json=json_data)
return res['pageData']
# 返回的识别结果是从右往左
"""
"pageData": [
{
"id": null,
"devId": "1000038",
"channelId": null,
"channelSeq": null,
"channelName": null,
"faceLibId": "1",
"libImgUrl": "6ad010cf-ce45-11ec-9715-e4246c7d1635/20220805/63/dsf_8c2487c1-14a1-11ed-880a-e4246c7d1635_2551349_2624751.jpg",
"faceImgUrl": null,
"hitImgUrl": null,
"identity": "342422199004040175",
"name": "曹前明",
"sex": "",
"nation": null,
"bornYear": null,
"age": null,
"glasses": null,
"fringe": null,
"similarity": 99,
"recTime": null,
"mask": null,
"beard": null,
"glass": null,
"maskStr": null,
"beardStr": null,
"glassStr": null,
"featureStr": "其他 ",
"groupName": "内部库1",
"groupType": 3,
"groupTypeStr": "内部库",
"identityType": 1,
"identityTypeStr": "身份证",
"birthday": null,
"searchGroupType": 2,
"birthdayStr": "2022-07-14",
"deviceName": "ivs服务器",
"personCode": "123"
},
{
"id": null,
"devId": "1000038",
"channelId": null,
"channelSeq": null,
"channelName": null,
"faceLibId": "1",
"libImgUrl": "6ad010cf-ce45-11ec-9715-e4246c7d1635/20220805/63/dsf_8c2487c1-14a1-11ed-880a-e4246c7d1635_2624751_2701750.jpg",
"faceImgUrl": null,
"hitImgUrl": null,
"identity": "371324199502156548",
"name": "石静",
"sex": "",
"nation": null,
"bornYear": null,
"age": null,
"glasses": null,
"fringe": null,
"similarity": 96,
"recTime": null,
"mask": null,
"beard": null,
"glass": null,
"maskStr": null,
"beardStr": null,
"glassStr": null,
"featureStr": "其他 ",
"groupName": "内部库1",
"groupType": 3,
"groupTypeStr": "内部库",
"identityType": 1,
"identityTypeStr": "身份证",
"birthday": null,
"searchGroupType": 2,
"birthdayStr": "2022-06-24",
"deviceName": "ivs服务器",
"personCode": "shijing"
}
]
"""
def face_bind(self):
# 人像绑定到主库
json_data = {
"deptId": 1,
"groupIdList": [settings.DAHUA_FACEGROUPID_1],
"cascade": True
}
self.request(**dhapis['face_bind'], json=json_data)
def face_deploy(self, minSim: int = 90):
params = {
"id": "001001001",
"checkStat": "1",
"type": "001;00_1;1",
"capability": "1_00000000000000000000000100000000",
"curCount": "0",
"isDomain": 0
}
_, res = self.request(**dhapis['dev_tree'], params=params)
for i in json.loads(res):
json_data = {
"minSimilarity": str(minSim),
"dpMinSimilarity": minSim,
"surveyType": ["1"],
"groups": str(settings.DAHUA_FACEGROUPID_1),
"chnId": i['id']
}
self.request(**dhapis['face_deploy'], json=json_data)
def get_rtsp(self, code: str):
"""获取rtsp流
Args:
code (str): 通道编号
"""
is_ok, res = self.request(**dhapis['video_rtsp'], json={"data": {"channelId": code,"dataType": "1","streamType": "1"}})
if is_ok == 'success':
if '|' in res['url']:
urls = res['url'].split('|')
for i in urls:
if settings.DAHUA_HOST in i:
return f"{i}?token={res['token']}"
else:
return f"{res['url']}?token={res['token']}"
return None
dhClient = DhClient()