deviceStatus.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. """
  5. import json
  6. import time
  7. import datetime
  8. from datetime import timezone
  9. import requests
  10. import uuid
  11. import logging
  12. from django.views.generic import TemplateView
  13. from django.http import JsonResponse
  14. import http.client
  15. from urllib.parse import urlencode
  16. from object.ResObject import ResObject
  17. import subprocess
  18. # from gevent.pool import Pool
  19. from model.models import UserModel, UidRtspModel, SwitchModel
  20. from object.ResponseObject import ResponseObject
  21. from object.tkObject import tkObject
  22. from service.CommonService import CommonService
  23. from model.models import AlexaAuthModel
  24. from object.RedisObject import RedisObject
  25. from django.utils.decorators import method_decorator
  26. from django.views.decorators.csrf import csrf_exempt
  27. from azoauth.config import *
  28. class deviceStatus(TemplateView):
  29. @method_decorator(csrf_exempt)
  30. def dispatch(self, *args, **kwargs):
  31. return super(deviceStatus, self).dispatch(*args, **kwargs)
  32. def get(self, request, *args, **kwargs):
  33. request.encoding = 'utf-8'
  34. operation = kwargs.get('operation')
  35. return self.validation(request.GET, request, operation)
  36. def post(self, request, *args, **kwargs):
  37. request.encoding = 'utf-8'
  38. operation = kwargs.get('operation')
  39. return self.validation(request.POST, request, operation)
  40. def validation(self, request_dict, request, operation):
  41. response = ResponseObject()
  42. if operation == 'saveAccessToken':
  43. return self.saveAccessToken(request_dict)
  44. elif operation == 'addOrUpdateV2':
  45. return self.addOrUpdateV2(request_dict)
  46. elif operation == 'addOrUpdateSwitch':
  47. return self.addOrUpdateSwitch(request_dict)
  48. elif operation == 'delete':
  49. return self.delete(request_dict)
  50. elif operation == 'stateReport':
  51. return self.StateReport(request_dict)
  52. elif operation == 'changeReportSwitch':
  53. return self.changeReportSwitch(request_dict)
  54. elif operation == 'deleteSwitch':
  55. return self.deleteSwitch(request_dict)
  56. def saveAccessToken(self, request_dict):
  57. token = request_dict.get("token", '')
  58. alexa_region = request_dict.get("region", '')
  59. skill_name = request_dict.get("skill_name", '')
  60. access_token = request_dict.get("access_token", '')
  61. refresh_token = request_dict.get("refresh_token", '')
  62. logger = logging.getLogger('django')
  63. logger.info('认证登录,参数: {}'.format(request_dict))
  64. try:
  65. alex_auth_qs = AlexaAuthModel.objects.filter(token=token, skill_name=skill_name)
  66. nowTime = int(time.time())
  67. if not alex_auth_qs.exists():
  68. AlexaAuthModel.objects.create(
  69. token=token,
  70. addTime=nowTime,
  71. updTime=nowTime,
  72. alexa_region=alexa_region,
  73. access_token=access_token,
  74. refresh_token=refresh_token,
  75. expiresTime=nowTime + 3200,
  76. skill_name=skill_name
  77. )
  78. else:
  79. alex_auth_qs.update(
  80. token=token,
  81. updTime=nowTime,
  82. alexa_region=alexa_region,
  83. access_token=access_token,
  84. refresh_token=refresh_token,
  85. expiresTime=nowTime + 3200,
  86. )
  87. # 更新业务服务器的token
  88. user_qs = UserModel.objects.filter(access_token=token).values('userID')
  89. if user_qs.exists():
  90. user_id = user_qs[0]['userID']
  91. if alexa_region == 'US':
  92. base_url = SERVER_PREFIX # SERVER_PREFIX, SERVER_PREFIX_TEST
  93. else:
  94. base_url = SERVER_PREFIX_EU
  95. url = '{}/alexaApi/appToApp/updateToken'.format(base_url)
  96. data = {
  97. 'user_id': user_id,
  98. 'access_token': access_token,
  99. 'refresh_token': refresh_token
  100. }
  101. r = requests.post(url=url, data=data, timeout=10)
  102. logger.info('请求更新token状态码: {}'.format(r.status_code))
  103. return JsonResponse({'code': 200, 'msg': 'success'})
  104. except Exception as e:
  105. logger.info('授权登录接口异常: error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  106. return JsonResponse({'code': 500, 'msg': 'error'})
  107. # 向alexa事件网关发送更新设备操作V2接口
  108. def addOrUpdateV2(self, request_dict):
  109. logger = logging.getLogger('django')
  110. logger.info('--------添加/更新设备信息V2--------')
  111. region = request_dict.get("region", 'EN')
  112. data_list = request_dict.get("data_list", '')
  113. logger.info('data_list: {}'.format(data_list))
  114. data_list = json.loads(data_list) # 多通道设备才传 channel 键值对
  115. if not data_list:
  116. return JsonResponse({'code': 101, 'msg': 'Parameter error'})
  117. try:
  118. UID = data_list[0]['UID']
  119. userID = data_list[0]['userID']
  120. password = data_list[0]['password']
  121. password = CommonService().decode_pwd(password)
  122. # 获取alexa授权信息
  123. alexAuth = AlexaAuthModel.objects.filter(userID=userID). \
  124. values('expiresTime', 'access_token', 'refresh_token', 'alexa_region', 'skill_name')
  125. if not alexAuth.exists():
  126. logger.info('UID为 {} 的用户不存在'.format(UID))
  127. return JsonResponse({'code': 102, 'msg': 'not found user'})
  128. skill_name = alexAuth[0]['skill_name']
  129. expiresTime = alexAuth[0]['expiresTime']
  130. access_token = alexAuth[0]['access_token']
  131. refresh_token = alexAuth[0]['refresh_token']
  132. alexa_region = alexAuth[0]['alexa_region']
  133. if alexa_region not in ALEXA_EVENT_API.keys():
  134. logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
  135. return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
  136. # 更新alexa token
  137. now_time = int(time.time())
  138. if now_time > expiresTime:
  139. logger.info(refresh_token)
  140. res = self.getRefreshToken(refresh_token, skill_name)
  141. logger.info(res)
  142. if 'error' not in res:
  143. alexAuth.update(
  144. updTime=now_time,
  145. expiresTime=now_time + 3000,
  146. access_token=res['access_token'],
  147. refresh_token=res['refresh_token'],
  148. )
  149. access_token = res['access_token']
  150. else:
  151. logger.info('get refresh_token fail')
  152. return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
  153. # 添加rtsp记录
  154. channel = len(data_list) # 列表的元素个数即通道数量
  155. rtsp_url = tkObject(rank=1).encrypt(data=UID)
  156. uid_rtsp_qs = UidRtspModel.objects.filter(uid__contains=UID)
  157. if not uid_rtsp_qs.exists():
  158. # 创建UidRtsp数据
  159. if channel == 1:
  160. # 单通道设备
  161. UidRtspModel.objects.create(user_id=userID, uid=UID, nick=data_list[0]['uid_nick'], region=region,
  162. rtsp_url=rtsp_url, password=password, addTime=now_time,
  163. updTime=now_time)
  164. else:
  165. # 多通道设备
  166. bulk = []
  167. for data in data_list:
  168. uid = UID + '_' + str(data['channel']) # 多通道设备: uid_通道号
  169. uidRtsp = UidRtspModel(user_id=userID, uid=uid, nick=data['uid_nick'], region=region,
  170. rtsp_url=rtsp_url, password=password, addTime=now_time, updTime=now_time)
  171. bulk.append(uidRtsp)
  172. UidRtspModel.objects.bulk_create(bulk)
  173. else:
  174. # 更新UidRtsp数据
  175. count = len(uid_rtsp_qs)
  176. if count != channel:
  177. return JsonResponse({'code': 103, 'msg': '通道数不匹配'})
  178. if count == 1:
  179. uid_rtsp_qs.update(nick=data_list[0]['uid_nick'], region=region, password=password, user_id=userID)
  180. else:
  181. # 多通道设备
  182. for data in data_list:
  183. uid = UID + '_' + str(data['channel']) # 多通道设备: uid_通道号
  184. UidRtspModel.objects.filter(uid=uid).update(nick=data['uid_nick'], region=region,
  185. user_id=userID, password=password)
  186. api_uri = ALEXA_EVENT_API[alexa_region]
  187. messageId = str(uuid.uuid4()).strip()
  188. bearer_access_token = "Bearer {access_token}".format(access_token=access_token)
  189. headers = {"content-type": "application/json", "Authorization": bearer_access_token}
  190. endpoints = self.append_endpoint(data_list, channel)
  191. payload_json = {
  192. "event": {
  193. "header": {
  194. "namespace": "Alexa.Discovery",
  195. "name": "AddOrUpdateReport",
  196. "payloadVersion": "3",
  197. "messageId": messageId,
  198. },
  199. "payload": {
  200. "endpoints": endpoints,
  201. "scope": {
  202. "type": "BearerToken",
  203. "token": 'sdf',
  204. },
  205. },
  206. }
  207. }
  208. logger.info('--------Alexa AddOrUpdateReport请求: url:{},data:{}--------'.format(api_uri, payload_json))
  209. response = requests.post(api_uri, json=payload_json, headers=headers)
  210. logger.info('--------Alexa AddOrUpdateReport响应: {}--------'.format(response))
  211. return JsonResponse({'res': 'success'})
  212. except Exception as e:
  213. logger.info('--------添加/更新设备信息V2异常--------:error_line:{}, error_msg:{}'.
  214. format(e.__traceback__.tb_lineno, repr(e)))
  215. # 向alexa事件网关发送更新设备操作接口
  216. def addOrUpdateSwitch(self, request_dict):
  217. logger = logging.getLogger('django')
  218. logger.info('--------添加/更新插座信息--------')
  219. region = request_dict.get("region", 'US')
  220. nick_name = request_dict.get("nick_name", '')
  221. serial_number = request_dict.get("serial_number", '')
  222. user_id = request_dict.get("user_id", '')
  223. logger.info('region: {}, nick_name: {}, serial_number: {}, user_id: {}'.format(region, nick_name, serial_number,
  224. user_id))
  225. skill_name = 'loocam'
  226. if not all([nick_name, serial_number, user_id]):
  227. return JsonResponse({'code': 101, 'msg': 'Parameter error'})
  228. try:
  229. # 获取alexa授权信息
  230. alexAuth = AlexaAuthModel.objects.filter(userID=user_id, skill_name=skill_name). \
  231. values('expiresTime', 'access_token', 'refresh_token', 'alexa_region')
  232. if not alexAuth.exists():
  233. logger.info('serial_number {} 的用户不存在'.format(serial_number))
  234. return JsonResponse({'code': 102, 'msg': 'not found user'})
  235. expiresTime = alexAuth[0]['expiresTime']
  236. access_token = alexAuth[0]['access_token']
  237. refresh_token = alexAuth[0]['refresh_token']
  238. alexa_region = alexAuth[0]['alexa_region']
  239. if alexa_region not in ALEXA_EVENT_API.keys():
  240. logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
  241. return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
  242. # 更新alexa token
  243. now_time = int(time.time())
  244. if now_time > expiresTime:
  245. logger.info(refresh_token)
  246. res = self.getRefreshToken(refresh_token, skill_name)
  247. logger.info(res)
  248. if 'error' not in res:
  249. alexAuth.update(
  250. updTime=now_time,
  251. expiresTime=now_time + 3000,
  252. access_token=res['access_token'],
  253. refresh_token=res['refresh_token'],
  254. )
  255. access_token = res['access_token']
  256. else:
  257. logger.info('get refresh_token fail')
  258. return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
  259. # 添加rtsp记录
  260. switch_qs = SwitchModel.objects.filter(serial_number=serial_number, userID=user_id)
  261. if switch_qs.exists():
  262. switch_qs.update(nick=nick_name, updTime=now_time)
  263. else:
  264. data = {
  265. 'nick': nick_name,
  266. 'serial_number': serial_number,
  267. 'userID': user_id,
  268. 'region': region,
  269. 'addTime': now_time,
  270. 'updTime': now_time,
  271. }
  272. SwitchModel.objects.create(**data)
  273. api_uri = ALEXA_EVENT_API[alexa_region]
  274. messageId = str(uuid.uuid4()).strip()
  275. bearer_access_token = "Bearer {access_token}".format(access_token=access_token)
  276. headers = {"content-type": "application/json", "Authorization": bearer_access_token}
  277. endpoints = [{
  278. "endpointId": serial_number,
  279. "manufacturerName": skill_name,
  280. "friendlyName": nick_name,
  281. "description": 'Plug connected via {}'.format(skill_name),
  282. "displayCategories": ['SMARTPLUG'],
  283. "cookie": {},
  284. "capabilities": [
  285. {
  286. "type": 'AlexaInterface',
  287. "interface": 'Alexa.PowerController',
  288. "version": '3',
  289. "properties": {
  290. "supported": [
  291. {
  292. "name": "powerState"
  293. }
  294. ],
  295. "proactivelyReported": True,
  296. "retrievable": True
  297. },
  298. },
  299. {
  300. "type": 'AlexaInterface',
  301. "interface": 'Alexa',
  302. "version": '3'
  303. }
  304. ]
  305. }]
  306. payload_json = {
  307. "event": {
  308. "header": {
  309. "namespace": "Alexa.Discovery",
  310. "name": "AddOrUpdateReport",
  311. "payloadVersion": "3",
  312. "messageId": messageId,
  313. },
  314. "payload": {
  315. "endpoints": endpoints,
  316. "scope": {
  317. "type": "BearerToken",
  318. "token": 'sdf',
  319. },
  320. },
  321. }
  322. }
  323. response = requests.post(api_uri, json=payload_json, headers=headers)
  324. logger.info('--------Alexa AddOrUpdateReport响应: {}--------'.format(response))
  325. return JsonResponse({'res': 'success'})
  326. except Exception as e:
  327. logger.info('--------添加/更新插座信息异常--------:error_line:{}, error_msg:{}'.
  328. format(e.__traceback__.tb_lineno, repr(e)))
  329. return JsonResponse({'res': 'error'})
  330. # 向alexa事件网关发送插座状态操作接口
  331. def StateReport(self, request_dict):
  332. logger = logging.getLogger('django')
  333. logger.info('--------alexa智能插座状态上报--------')
  334. serial_number = request_dict.get("serial_number", None)
  335. access_token = request_dict.get("access_token", None)
  336. logger.info('请求参数: {}'.format(request_dict))
  337. response = ResObject()
  338. if not all([serial_number, access_token]):
  339. return response.json(10, res={'msg': 'Parameter error'})
  340. user_qs = UserModel.objects.filter(access_token=access_token)
  341. if not user_qs.exists():
  342. return response.json(10, res={'msg': '用户数据不存在'})
  343. user_id = user_qs.first().userID
  344. switch_qs = SwitchModel.objects.filter(serial_number=serial_number).values('region')
  345. if not switch_qs.exists():
  346. return response.json(10, res={'msg': '设备不存在'})
  347. try:
  348. region = switch_qs[0]['region']
  349. if region == 'EU':
  350. domain_name = SERVER_PREFIX_EU
  351. elif region == 'CN':
  352. domain_name = SERVER_PREFIX_TEST
  353. else:
  354. domain_name = SERVER_PREFIX
  355. auth_request_url = '{}/api/loocam/open/socket/getSocketState'.format(domain_name)
  356. requests_data = {'serial_number': serial_number, 'alexa_user_id': user_id}
  357. res = requests.post(url=auth_request_url, data=requests_data)
  358. res_json = res.json()
  359. logger.info('{}正式服务器响应: {}'.format(region, res_json))
  360. if res_json['result_code'] != 0:
  361. return response.json(10, res={'msg': 'error'})
  362. power_state = res_json['result']['power_state']
  363. if power_state:
  364. res = {'state': 'ON'}
  365. else:
  366. res = {'state': 'OFF'}
  367. return response.json(0, res=res)
  368. except Exception as e:
  369. logger.info('--------上传插座状态异常--------:error_line:{}, error_msg:{}'.
  370. format(e.__traceback__.tb_lineno, repr(e)))
  371. return response.json(10, res={'msg': '上报状态异常'})
  372. def append_endpoint(self, data_list, channel):
  373. # 组织 endpoints 数据
  374. endpoints = []
  375. for data in data_list:
  376. endpointId = data['UID'] if channel == 1 else data['UID'] + '_' + str(data['channel'])
  377. endpoint = {
  378. "endpointId": endpointId,
  379. "manufacturerName": "zosi smart",
  380. "modelName": "P1425-LE",
  381. "friendlyName": data['uid_nick'],
  382. "description": "Camera connected via zosi smart",
  383. "displayCategories": ["CAMERA"],
  384. "capabilities": [
  385. {
  386. "type": "AlexaInterface",
  387. "interface": "Alexa.CameraStreamController",
  388. "version": "3",
  389. "cameraStreamConfigurations": [
  390. {
  391. "protocols": ["RTSP"],
  392. "resolutions": [{"width": 1280, "height": 720}],
  393. "authorizationTypes": ["NONE"],
  394. "videoCodecs": ["H264"],
  395. "audioCodecs": ["ACC"],
  396. }
  397. ],
  398. }
  399. ],
  400. }
  401. endpoints.append(endpoint)
  402. return endpoints
  403. # 向alexa事件网关发送删除设备操作
  404. def delete(self, request_dict):
  405. UID = request_dict.get("UID", '')
  406. userID = request_dict.get("userID", '')
  407. logger = logging.getLogger('django')
  408. logger.info('--------删除设备--------')
  409. logger.info('userID: {}, UID: {}'.format(userID, UID))
  410. if not all([UID, userID]):
  411. return JsonResponse({'code': 111, 'msg': 'fail'})
  412. try:
  413. alexAuth = AlexaAuthModel.objects.filter(userID=userID). \
  414. values('expiresTime', 'refresh_token', 'access_token', 'alexa_region', 'skill_name')
  415. if not alexAuth.exists():
  416. logger.info('UID为 {} 的用户不存在'.format(UID))
  417. return JsonResponse({'code': 102, 'msg': 'not found user'})
  418. skill_name = alexAuth[0]['skill_name']
  419. expiresTime = alexAuth[0]['expiresTime']
  420. refresh_token = alexAuth[0]['refresh_token']
  421. access_token = alexAuth[0]['access_token']
  422. alexa_region = alexAuth[0]['alexa_region']
  423. if alexa_region not in ALEXA_EVENT_API.keys():
  424. logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
  425. return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
  426. now_time = int(time.time())
  427. if now_time > expiresTime:
  428. res = self.getRefreshToken(refresh_token, skill_name)
  429. if 'error' not in res:
  430. alexAuth.update(
  431. access_token=res['access_token'],
  432. refresh_token=res['refresh_token'],
  433. expiresTime=now_time + 300,
  434. updTime=now_time,
  435. )
  436. access_token = res['access_token']
  437. else:
  438. return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
  439. uidRtsp_qs = UidRtspModel.objects.filter(uid__contains=UID).values('uid')
  440. if not uidRtsp_qs.exists():
  441. return JsonResponse({'code': 103, 'msg': '不存在uidRtsp数据'})
  442. endpoints = []
  443. for uidRtsp in uidRtsp_qs:
  444. endpointId = {"endpointId": uidRtsp['uid']}
  445. endpoints.append(endpointId)
  446. headers = {
  447. "Authorization": "Bearer " + access_token,
  448. "Content-Type": "application/json;charset=UTF-8",
  449. "Cache-Control": "no-cache"
  450. }
  451. payload = {
  452. "event": {
  453. "header": {
  454. "namespace": "Alexa.Discovery",
  455. "name": "DeleteReport",
  456. "messageId": str(uuid.uuid4()),
  457. "payloadVersion": "3"
  458. },
  459. "payload": {
  460. "endpoints": endpoints,
  461. "scope": {
  462. "type": "BearerToken",
  463. "token": access_token
  464. }
  465. }
  466. }
  467. }
  468. api_uri = ALEXA_EVENT_API[alexa_region]
  469. response = requests.post(api_uri, json=payload, headers=headers)
  470. logger.info('--------Alexa DeleteReport响应: {}--------'.format(response))
  471. return JsonResponse({'res': 'success'})
  472. except Exception as e:
  473. logger.info('--------删除设备异常--------:error_line:{}, error_msg:{}'.
  474. format(e.__traceback__.tb_lineno, repr(e)))
  475. def changeReportSwitch(self, request_dict):
  476. # 通过app或设备打开/关闭插座电源时主动报告状态
  477. serial_number = request_dict.get('serial_number')
  478. value = request_dict.get('value')
  479. cause_type = request_dict.get('cause_type')
  480. logger = logging.getLogger('django')
  481. logger.info('插座ChangeReport,serial_number:{}, value:{}, cause_type:{}'.format(serial_number, value, cause_type))
  482. if not all([serial_number, value, cause_type]):
  483. return JsonResponse({'code': 111, 'msg': '参数异常'})
  484. skill_name = 'loocam'
  485. try:
  486. switch_qs = SwitchModel.objects.filter(serial_number=serial_number)
  487. if not switch_qs.exists():
  488. return JsonResponse({'code': 103, 'msg': '不存在socket数据'})
  489. userID = switch_qs[0].userID
  490. alexAuth = AlexaAuthModel.objects.filter(userID=userID, skill_name=skill_name). \
  491. values('expiresTime', 'refresh_token', 'access_token', 'alexa_region')
  492. if not alexAuth.exists():
  493. logger.info('序列号为 {} 的用户不存在'.format(serial_number))
  494. return JsonResponse({'code': 102, 'msg': 'not found user'})
  495. expiresTime = alexAuth[0]['expiresTime']
  496. refresh_token = alexAuth[0]['refresh_token']
  497. access_token = alexAuth[0]['access_token']
  498. alexa_region = alexAuth[0]['alexa_region']
  499. if alexa_region not in ALEXA_EVENT_API.keys():
  500. logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
  501. return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
  502. now_time = int(time.time())
  503. if now_time > expiresTime:
  504. res = self.getRefreshToken(refresh_token, skill_name)
  505. if 'error' not in res:
  506. alexAuth.update(
  507. access_token=res['access_token'],
  508. refresh_token=res['refresh_token'],
  509. expiresTime=now_time + 300,
  510. updTime=now_time,
  511. )
  512. access_token = res['access_token']
  513. else:
  514. return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
  515. headers = {
  516. "Authorization": "Bearer " + access_token,
  517. "Content-Type": "application/json;charset=UTF-8",
  518. "Cache-Control": "no-cache"
  519. }
  520. # 转换时间格式
  521. iso_string = datetime.datetime.now(timezone.utc).isoformat()
  522. time_of_sample = iso_string.split('.')[0] + 'Z'
  523. payload = {
  524. "event": {
  525. "header": {
  526. "namespace": "Alexa",
  527. "name": "ChangeReport",
  528. "messageId": str(uuid.uuid4()),
  529. "payloadVersion": "3"
  530. },
  531. "endpoint": {
  532. "scope": {
  533. "type": "BearerToken",
  534. "token": access_token
  535. },
  536. "endpointId": serial_number
  537. },
  538. "payload": {
  539. "change": {
  540. "cause": {
  541. "type": cause_type
  542. },
  543. "properties": [
  544. {
  545. "namespace": "Alexa.PowerController",
  546. "name": "powerState",
  547. "value": value,
  548. "timeOfSample": time_of_sample,
  549. "uncertaintyInMilliseconds": 0
  550. }
  551. ]
  552. }
  553. }
  554. }
  555. }
  556. api_uri = ALEXA_EVENT_API[alexa_region]
  557. response = requests.post(api_uri, json=payload, headers=headers)
  558. logger.info('--------Alexa ChangeReport响应: {}--------'.format(response))
  559. return JsonResponse({'res': 'success'})
  560. except Exception as e:
  561. logger.info('--------插座ChangeReport异常--------:error_line:{}, error_msg:{}'.
  562. format(e.__traceback__.tb_lineno, repr(e)))
  563. return JsonResponse({'res': 'error'})
  564. # 向alexa事件网关发送删除插座操作
  565. def deleteSwitch(self, request_dict):
  566. serial_number = request_dict.get("serial_number", '')
  567. logger = logging.getLogger('django')
  568. logger.info('--------删除插座--------')
  569. logger.info('serial_number: {}'.format(serial_number))
  570. if not all([serial_number]):
  571. return JsonResponse({'code': 111, 'msg': '参数异常'})
  572. skill_name = 'loocam'
  573. try:
  574. switch_qs = SwitchModel.objects.filter(serial_number=serial_number)
  575. if not switch_qs.exists():
  576. return JsonResponse({'code': 103, 'msg': '不存在socket数据'})
  577. userID = switch_qs[0].userID
  578. alexAuth = AlexaAuthModel.objects.filter(userID=userID, skill_name=skill_name). \
  579. values('expiresTime', 'refresh_token', 'access_token', 'alexa_region')
  580. if not alexAuth.exists():
  581. logger.info('序列号为 {} 的用户不存在'.format(serial_number))
  582. return JsonResponse({'code': 102, 'msg': 'not found user'})
  583. expiresTime = alexAuth[0]['expiresTime']
  584. refresh_token = alexAuth[0]['refresh_token']
  585. access_token = alexAuth[0]['access_token']
  586. alexa_region = alexAuth[0]['alexa_region']
  587. if alexa_region not in ALEXA_EVENT_API.keys():
  588. logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
  589. return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
  590. now_time = int(time.time())
  591. if now_time > expiresTime:
  592. res = self.getRefreshToken(refresh_token, skill_name)
  593. if 'error' not in res:
  594. alexAuth.update(
  595. access_token=res['access_token'],
  596. refresh_token=res['refresh_token'],
  597. expiresTime=now_time + 300,
  598. updTime=now_time,
  599. )
  600. access_token = res['access_token']
  601. else:
  602. return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
  603. endpoints = []
  604. for switch in switch_qs:
  605. endpointId = {"endpointId": switch.serial_number}
  606. endpoints.append(endpointId)
  607. switch_qs.delete()
  608. headers = {
  609. "Authorization": "Bearer " + access_token,
  610. "Content-Type": "application/json;charset=UTF-8",
  611. "Cache-Control": "no-cache"
  612. }
  613. payload = {
  614. "event": {
  615. "header": {
  616. "namespace": "Alexa.Discovery",
  617. "name": "DeleteReport",
  618. "messageId": str(uuid.uuid4()),
  619. "payloadVersion": "3"
  620. },
  621. "payload": {
  622. "endpoints": endpoints,
  623. "scope": {
  624. "type": "BearerToken",
  625. "token": access_token
  626. }
  627. }
  628. }
  629. }
  630. api_uri = ALEXA_EVENT_API[alexa_region]
  631. response = requests.post(api_uri, json=payload, headers=headers)
  632. logger.info('--------Alexa DeleteReport响应: {}--------'.format(response))
  633. return JsonResponse({'res': 'success'})
  634. except Exception as e:
  635. logger.info('--------删除设备异常--------:error_line:{}, error_msg:{}'.
  636. format(e.__traceback__.tb_lineno, repr(e)))
  637. return JsonResponse({'res': 'error'})
  638. def getRefreshToken(self, refresh_token, skill_name):
  639. # 请求更新token
  640. logger = logging.getLogger('django')
  641. logger.info('--------{}请求更新token--------'.format(skill_name))
  642. if skill_name not in CLIENT_CONFIG.keys():
  643. # skill_name = 'Anlapus' # 应对UL测试,后期改回
  644. logger.info('--------技能名称错误,skill_name: {}--------'.format(skill_name))
  645. return JsonResponse({'code': 111, 'msg': 'skill_name error'})
  646. payload = {
  647. 'grant_type': 'refresh_token',
  648. 'refresh_token': refresh_token,
  649. 'client_id': CLIENT_CONFIG[skill_name]['client_id'],
  650. 'client_secret': CLIENT_CONFIG[skill_name]['client_secret'],
  651. }
  652. auth_request_url = 'https://api.amazon.com/auth/o2/token'
  653. headers = {
  654. 'content-type': "application/x-www-form-urlencoded",
  655. 'cache-control': "no-cache"
  656. }
  657. res = requests.post(auth_request_url, payload, headers)
  658. request_json = res.json()
  659. return request_json