utils.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. import string
  2. import random
  3. import requests
  4. import json
  5. import logging
  6. import time
  7. import hashlib
  8. import math
  9. from captcha.image import ImageCaptcha
  10. from io import BytesIO
  11. import base64
  12. from datetime import datetime, timedelta
  13. import calendar
  14. from smartfarming.models.user import Role, UserPurview
  15. from kedong.tools import RedisPool
  16. from kedong import settings
  17. logger = logging.getLogger("other")
  18. redis_pool = RedisPool().get_redis_pool(settings.redis_db["jiankong"])
  19. config = settings.CONFIG
  20. def perms_pc_app(type_id=1000, perms_lst=[], device_user=None):
  21. menu = "PC" if type_id == 1000 else "APP"
  22. if menu == "APP":
  23. children_lst = []
  24. apps = UserPurview.objects.filter(menu=menu)
  25. for i in apps:
  26. children_lst.append(
  27. {
  28. "menu": "APP",
  29. "parent_perm_id": 99,
  30. "pur_id": i.id,
  31. "purview_name": i.purview_name,
  32. "url": i.url
  33. }
  34. )
  35. return children_lst
  36. else:
  37. parent_ids = []
  38. for p in perms_lst:
  39. # 先判断是否是父级菜单
  40. per_obj = UserPurview.objects.filter(id=int(p), menu=menu).first()
  41. if per_obj:
  42. if per_obj.parent_perm_id == 0:
  43. parent_ids.append(p)
  44. perm_lst = []
  45. for i in parent_ids:
  46. parent = UserPurview.objects.get(id=int(i), menu=menu)
  47. inner_parent = {
  48. "menu": parent.menu,
  49. "parent_perm_id": parent.parent_perm_id,
  50. "pur_id": parent.id,
  51. "purview_name": parent.purview_name,
  52. "url": parent.url
  53. }
  54. children_lst = []
  55. # 获取此父级菜单中所有的子菜单
  56. children = UserPurview.objects.filter(parent_perm_id=int(i), menu=menu)
  57. for child in children:
  58. if child.id in perms_lst:
  59. if device_user and device_user.real_name == "yunfei" and child.parent_perm_id == 1:
  60. children_lst.append(
  61. {
  62. "menu": child.menu,
  63. "parent_perm_id": child.parent_perm_id,
  64. "pur_id": child.id,
  65. "purview_name": child.purview_name,
  66. "url": child.url
  67. }
  68. )
  69. if child.purview_name == "用户管理":
  70. children_lst.append(
  71. {
  72. "menu": "PC",
  73. "parent_perm_id": 0,
  74. "pur_id": 38,
  75. "purview_name": "监控定位",
  76. "url": "0"
  77. }
  78. )
  79. children_lst.append(
  80. {
  81. "menu": "PC",
  82. "parent_perm_id": 0,
  83. "pur_id": 39,
  84. "purview_name": "APP信息",
  85. "url": "0"
  86. }
  87. )
  88. else:
  89. children_lst.append(
  90. {
  91. "menu": child.menu,
  92. "parent_perm_id": child.parent_perm_id,
  93. "pur_id": child.id,
  94. "purview_name": child.purview_name,
  95. "url": child.url
  96. }
  97. )
  98. if children_lst:
  99. inner_parent["children"] = children_lst
  100. perm_lst.append(inner_parent)
  101. return perm_lst
  102. def get_perm_list(device_user):
  103. id = device_user.role_id
  104. try:
  105. role = Role.objects.get(id=id)
  106. role_perm = role.role_perm
  107. perms_lst = [int(i) for i in role_perm.split(",")]
  108. pc_perm_lst = perms_pc_app(type_id=1000, perms_lst=perms_lst, device_user=device_user)
  109. app_perm_lst = perms_pc_app(type_id=2000, perms_lst=perms_lst)
  110. if pc_perm_lst and app_perm_lst:
  111. perm_lst = [
  112. {
  113. "menu": "",
  114. "parent_perm_id": 1000,
  115. "pur_id": 0,
  116. "purview_name": "登录PC端",
  117. "url": "",
  118. "children": pc_perm_lst
  119. },
  120. {
  121. "menu": "",
  122. "parent_perm_id": 2000,
  123. "pur_id": 99,
  124. "purview_name": "登录APP端",
  125. "url": "",
  126. "children": app_perm_lst
  127. }
  128. ]
  129. elif pc_perm_lst:
  130. perm_lst = [
  131. {
  132. "menu": "",
  133. "parent_perm_id": 1000,
  134. "pur_id": 0,
  135. "purview_name": "登录PC端",
  136. "url": "",
  137. "children": pc_perm_lst
  138. }
  139. ]
  140. elif app_perm_lst:
  141. perm_lst = [
  142. {
  143. "menu": "",
  144. "parent_perm_id": 2000,
  145. "pur_id": 99,
  146. "purview_name": "登录APP端",
  147. "url": "",
  148. "children": app_perm_lst
  149. }
  150. ]
  151. else:
  152. perm_lst = []
  153. mark = role.mark
  154. return perm_lst, mark
  155. except Exception as e:
  156. return [], ""
  157. def get_all_pers():
  158. role_perm = UserPurview.objects.all().values("id")
  159. perms_lst = []
  160. for i in role_perm:
  161. perms_lst.append(i.get("id"))
  162. pc_perm_lst = perms_pc_app(type_id=1000, perms_lst=perms_lst)
  163. app_perm_lst = perms_pc_app(type_id=2000, perms_lst=perms_lst)
  164. perm_lst = [
  165. {
  166. "menu": "",
  167. "parent_perm_id": 1000,
  168. "pur_id": 0,
  169. "purview_name": "登录PC端",
  170. "url": "",
  171. "children": pc_perm_lst
  172. },
  173. {
  174. "menu": "",
  175. "parent_perm_id": 2000,
  176. "pur_id": 99,
  177. "purview_name": "登录APP端",
  178. "url": "",
  179. "children": app_perm_lst
  180. }
  181. ]
  182. return perm_lst
  183. def get_captcha():
  184. """获取图片验证码
  185. return :
  186. 验证码字符串,验证码图片base64数据
  187. """
  188. chr_all = string.ascii_uppercase + string.digits
  189. chr_all = chr_all.replace('0', '').replace('1', '').replace('2', '').replace('O', '').replace('I', '')
  190. code_str = ''.join(random.sample(chr_all, 4))
  191. image = ImageCaptcha().generate_image(code_str)
  192. f = BytesIO()
  193. image.save(f, 'png')
  194. data = f.getvalue()
  195. f.close()
  196. encode_data = base64.b64encode(data)
  197. data = str(encode_data, encoding='utf-8')
  198. img_data = "data:image/jpeg;base64,{data}".format(data=data)
  199. return code_str, img_data
  200. def get_recent_month(num):
  201. # 获取最近N个月的时间戳
  202. end_time = datetime.now() # 结束时间,当前时间
  203. # 获取当前月份和年份
  204. current_month = end_time.month
  205. current_year = end_time.year
  206. # 计算开始时间
  207. start_month = current_month - num # 当前月份往前推N个月
  208. start_year = current_year
  209. if start_month <= 0: # 如果计算得到的月份为负数,则需要向前借位
  210. start_month += 12
  211. start_year -= 1
  212. # 获取开始时间所在月份的最后一天
  213. _, last_day = calendar.monthrange(start_year, start_month)
  214. start_time = datetime(start_year, start_month, last_day).timestamp()
  215. return start_time
  216. def get_addr_by_lag_lng(lat,lng):
  217. # 根据经纬度获取省市级
  218. is_success, province, city, district = False, "", "", ""
  219. try:
  220. # 使用腾讯接口
  221. url = "https://apis.map.qq.com/ws/geocoder/v1?location={},{}&get_poi=0&key=OA4BZ-FX43U-E5VV2-45M6S-C4HD3-NIFFI&output=json".format(lat,lng)
  222. requests.adapters.DEFAULT_RETRIES = 5 # 增加重连次数
  223. s = requests.session()
  224. s.keep_alive = False # 关闭多余连接
  225. ret = s.get(url)
  226. rest = json.loads(ret.text)
  227. province = rest["result"]["ad_info"]["province"]
  228. city = rest["result"]["ad_info"]["city"]
  229. district = rest["result"]["ad_info"]["district"]
  230. is_success = True
  231. except Exception as e:
  232. logger.error(f"获取腾讯地理位置接口失败 {e.args}")
  233. if not is_success:
  234. try:
  235. # 使用百度接口
  236. url = "http://api.map.baidu.com/geocoder?location=%s,%s&output=json"%(lat,lng)
  237. requests.adapters.DEFAULT_RETRIES = 5 # 增加重连次数
  238. s = requests.session()
  239. s.keep_alive = False # 关闭多余连接
  240. ret = s.get(url)
  241. addr = json.loads(ret.text)
  242. province = addr["result"]["addressComponent"]["province"]
  243. city = addr["result"]["addressComponent"]["city"]
  244. district = addr["result"]["addressComponent"]["district"]
  245. is_success = True
  246. except Exception as e:
  247. logger.error(f"获取百度地理位置接口失败 {e.args}")
  248. return is_success, province, city, district
  249. # 获取天气数据
  250. def get_address_by_lntlat(lng, lat):
  251. province, city, district = "", "", ""
  252. try:
  253. key = "78ce288400f4fc6d9458989875c833c2"
  254. adcode_url = "http://restapi.amap.com/v3/geocode/regeo?key={key}&location={lng},{lat}&poitype=&radius=&" \
  255. "extensions=all&batch=false&roadlevel=0".format(key=key, lng=lng, lat=lat)
  256. res = requests.get(adcode_url)
  257. rsp = res.json()
  258. address_info = rsp['regeocode']['addressComponent']
  259. adcode = address_info['adcode']
  260. if adcode != "900000":
  261. province, city, district = address_info['province'], address_info['city'], address_info['district']
  262. if (not city) and district:
  263. city = district
  264. except Exception as e:
  265. pass
  266. return province, city, district
  267. # 获取天气相关信息
  268. def get_weather_info(lng=None, lat=None):
  269. data = {}
  270. if lng and lat:
  271. try:
  272. url = "http://114.115.147.140:8080/weather"
  273. res = requests.post(url, {"lat": lat, "lng": lng})
  274. result = res.json()
  275. if result['status'] == 'true':
  276. data = result['data']
  277. except Exception as e:
  278. pass
  279. return data
  280. def expire_time(times):
  281. data_time = datetime.datetime.now()
  282. cultivate_time_expire = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(times))
  283. time1 = datetime.datetime.strptime(cultivate_time_expire,"%Y-%m-%d %H:%M:%S")
  284. num=(time1-data_time).days
  285. print("设备到期天数---",num)
  286. if int(num) <=7 and int(num) >= 0:
  287. print("即将到期")
  288. status = 2
  289. elif int(num) < 0:
  290. print("已到期")
  291. status = 1
  292. else:
  293. print("未到期")
  294. status = 0
  295. return status
  296. def get_center_lnglat(lnglats_list):
  297. x, y, z = 0, 0, 0
  298. length = len(lnglats_list)
  299. for n, a in lnglats_list:
  300. g, t = math.radians(float(n)), math.radians(float(a))
  301. x += math.cos(t) * math.cos(g)
  302. y += math.cos(t) * math.sin(g)
  303. z += math.sin(t)
  304. x = float(x / length)
  305. y = float(y / length)
  306. z = float(z / length)
  307. lng = round(math.degrees(math.atan2(y, x)), 4)
  308. lat = round(math.degrees(math.atan2(z, math.sqrt(x*x + y*y))), 4)
  309. return lng, lat
  310. def md5value(appSecret):
  311. """sign加密"""
  312. times = int(time.time())
  313. # 随机生成32位字符串
  314. nonce = ''.join(random.sample(string.ascii_letters + string.digits, 32))
  315. sign = "time:{},nonce:{},appSecret:{}".format(times, nonce, appSecret)
  316. input_name = hashlib.md5()
  317. input_name.update(sign.encode("utf-8"))
  318. sign = (input_name.hexdigest()).lower()
  319. return times,nonce,sign
  320. def deviceAccessToken(appId, appSecret):
  321. # 乐橙云账号秘钥
  322. # 先从redis 中获取token
  323. tokens = redis_pool.get(appId)
  324. if tokens and tokens !=None:
  325. redis_jk_data = eval(tokens)
  326. status = redis_jk_data.get("status",1)
  327. if status:
  328. # 查看到期时间
  329. expireTime = redis_pool.ttl(appId)
  330. # 设置到期时间 秒
  331. # redis_pool.expire('ttt', 10)
  332. redis_jk_data["result"]["data"]["expireTime"] = expireTime
  333. else:
  334. redis_jk_data = {"status":0}
  335. return redis_jk_data
  336. else:
  337. status = 0
  338. if not status:
  339. url = config.get("camera").get("lc_token")
  340. # 加密
  341. times,nonce,sign = md5value(appSecret)
  342. data = {
  343. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":times,"nonce":nonce},
  344. "id":nonce,
  345. "params":{}
  346. }
  347. token_data = requests.post(url,json=data, timeout=5)
  348. if token_data.status_code == 200:
  349. try:
  350. token_json_data = json.loads(token_data.text)
  351. expireTime = token_json_data["result"]["data"]["expireTime"]
  352. # status 1 代表获取token 成功 0失败
  353. token_json_data["status"] = 1
  354. except Exception as e:
  355. token_json_data = {"status":0}
  356. expireTime = 5
  357. else:
  358. token_json_data = {"status":0}
  359. expireTime = 5
  360. redis_pool.set(appId,str(token_json_data),expireTime)
  361. return token_json_data
  362. def device_config(appId,appSecret):
  363. # 配置项
  364. time,nonce,sign = md5value(appSecret)
  365. token_data = deviceAccessToken(appId, appSecret)
  366. if token_data.get("status","0"):
  367. token = token_data["result"]["data"]["accessToken"]
  368. else:
  369. token = ""
  370. return time,nonce,sign,token
  371. def controlMove(appId,appSecret,deviceId,operation,channelId="0"):
  372. # 云台控制接口
  373. url = config.get("camera").get("lc_controler")
  374. time,nonce,sign,token = device_config(appId, appSecret)
  375. if not token:
  376. return {"msg":"控制失败"}
  377. data = {
  378. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  379. "id":nonce,
  380. "params":{"token":token,"deviceId":deviceId,"channelId":channelId,"operation":operation,"duration":"1000"}
  381. }
  382. control_Move = requests.post(url,json=data)
  383. return control_Move.json()
  384. def bindDeviceLive(appId,appSecret,deviceId,channelId="0"):
  385. # 获取直播地址
  386. url = config.get("camera").get("lc_addr")
  387. time,nonce,sign,token = device_config(appId, appSecret)
  388. data = {
  389. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  390. "params":{"streamId":1,"deviceId":deviceId,"channelId":channelId,"token":token},
  391. "id":nonce
  392. }
  393. device_live_data = requests.post(url,json=data)
  394. return device_live_data.json()
  395. def getLive(appId,appSecret,deviceId,channelId="0"):
  396. # 查询监控地址 用于设备直播地址创建后再次查询使用
  397. url = config.get("camera").get("lc_stream")
  398. time,nonce,sign,token = device_config(appId, appSecret)
  399. data = {
  400. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  401. "params":{"deviceId":deviceId, "channelId":channelId,"token":token},
  402. "id":nonce
  403. }
  404. live_data = requests.post(url,json=data)
  405. return live_data.json()
  406. def modify_live_time(appId,appSecret,liveToken,start_time,end_time,period="everyday"):
  407. # 开启,修改直播计划时间
  408. # period 直播周期,always:永久,once:指定某天, everyday:每天
  409. url = config.get("camera").get("lc_modify_live_plan")
  410. time,nonce,sign,token = device_config(appId, appSecret)
  411. if not token:
  412. return {'result': {'msg': '获取token失败。', 'code': '1'}, 'id': 'rWfBFgohj7VwkxsqbM5p4JKDOtQNU2XA'}
  413. data = {
  414. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  415. "id":nonce,
  416. "params":{"token":token,"period":period,"liveToken":liveToken,"beginTime":start_time,"endTime": end_time}
  417. }
  418. if period == "always":
  419. del data["params"]["beginTime"]
  420. del data["params"]["endTime"]
  421. device_live_data = requests.post(url,json=data).json()
  422. return device_live_data
  423. def off_on_live(appId,appSecret,liveToken,status):
  424. # 关闭、开启当前直播
  425. url = config.get("camera").get("lc_modify_live_plan_status")
  426. time,nonce,sign,token = device_config(appId, appSecret)
  427. if not token:
  428. return {'result': {'msg': '获取token失败。', 'code': '1'}, 'id': 'rWfBFgohj7VwkxsqbM5p4JKDOtQNU2XA'}
  429. data = {
  430. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  431. "params":{"token":token,"liveToken":liveToken,"status":status},
  432. "id":nonce
  433. }
  434. device_live_data = requests.post(url,json=data).json()
  435. return device_live_data
  436. def setDeviceSnap(appId,appSecret,deviceId,channelId="0"):
  437. # 抓图接口
  438. url = config.get("camera").get("lc_device_snap_enhanced")
  439. # url = config.get("camera").get("lc_device_snap")
  440. time,nonce,sign,token = device_config(appId, appSecret)
  441. if not token:
  442. return {"msg": "抓图失败"}
  443. data = {
  444. "system":{"ver":"1.0", "appId":appId,"sign":sign,"time":time,"nonce":nonce},
  445. "params":{"deviceId":deviceId,"channelId":channelId,"token":token},
  446. "id":nonce
  447. }
  448. img_data = requests.post(url,json=data)
  449. result = img_data.json()
  450. if result.get("result").get("code") == "0":
  451. return result.get("result").get("data").get("url")
  452. def get_weather(ip):
  453. # 获取天气
  454. res = requests.get("http://v0.yiketianqi.com/api?unescape=1&version=v91&appid=69334222&appsecret=2u4bHXHD&ext=")
  455. response = json.loads(res.text)
  456. return response.get("data")
  457. def getKitToken(appId,appSecret,deviceId,channelId="0"):
  458. # 获取录像回放所需要的token
  459. url = config.get("camera").get("lc_kit_token")
  460. time,nonce,sign,token = device_config(appId, appSecret)
  461. if not token:
  462. return {"result":{"code":"1"}}
  463. data = {
  464. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  465. "id":nonce,
  466. "params":{"type":0,"deviceId":deviceId,"channelId":channelId,"token":token}
  467. }
  468. like_token_data = requests.post(url,json=data)
  469. return like_token_data.json()
  470. def getRecord(appId,appSecret,deviceId,channelId="0"):
  471. url = config.get("camera").get("lc_local_record")
  472. time,nonce,sign,token = device_config(appId, appSecret)
  473. if not token:
  474. return {"result":{"code":"1"}}
  475. data = {
  476. "system":{"ver":"1.0","appId":appId,"sign":sign,"time":time,"nonce":nonce},
  477. "id":nonce,
  478. "params":{
  479. "deviceId":deviceId,
  480. "channelId":channelId,
  481. "token":token,
  482. "beginTime":"2023-07-19 00:00:00",
  483. "endTime": "2023-07-25 00:00:00",
  484. "type": "All",
  485. "count": 100
  486. }
  487. }
  488. record_token_data = requests.post(url,json=data)
  489. return record_token_data.json()
  490. if __name__ == "__main__":
  491. t = get_recent_month(1)
  492. print(t)