123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- """
- import json
- import time, datetime
- import requests
- import uuid
- import logging
- from django.views.generic import TemplateView
- from django.http import JsonResponse
- import http.client
- from urllib.parse import urlencode
- from object.ResObject import ResObject
- import subprocess
- # from gevent.pool import Pool
- from model.models import UserModel, UidRtspModel, SwitchModel
- from object.ResponseObject import ResponseObject
- from object.tkObject import tkObject
- from service.CommonService import CommonService
- from model.models import AlexaAuthModel
- from object.RedisObject import RedisObject
- from django.utils.decorators import method_decorator
- from django.views.decorators.csrf import csrf_exempt
- from azoauth.config import *
- class deviceStatus(TemplateView):
- @method_decorator(csrf_exempt)
- def dispatch(self, *args, **kwargs):
- return super(deviceStatus, self).dispatch(*args, **kwargs)
- def get(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- return self.validation(request.GET, request, operation)
- def post(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- return self.validation(request.POST, request, operation)
- def validation(self, request_dict, request, operation):
- response = ResponseObject()
- if operation == 'saveAccessToken':
- return self.saveAccessToken(request_dict)
- elif operation == 'addOrUpdateV2':
- return self.addOrUpdateV2(request_dict)
- elif operation == 'addOrUpdateSwitch':
- return self.addOrUpdateSwitch(request_dict)
- elif operation == 'delete':
- return self.delete(request_dict)
- elif operation == 'stateReport':
- return self.StateReport(request_dict)
- elif operation == 'deleteSwitch':
- return self.deleteSwitch(request_dict)
- def saveAccessToken(self, request_dict):
- token = request_dict.get("token", '')
- alexa_region = request_dict.get("region", '')
- skill_name = request_dict.get("skill_name", '')
- access_token = request_dict.get("access_token", '')
- refresh_token = request_dict.get("refresh_token", '')
- logger = logging.getLogger('django')
- logger.info('认证登录,参数: {}'.format(request_dict))
- try:
- alex_auth_qs = AlexaAuthModel.objects.filter(token=token, skill_name=skill_name)
- nowTime = int(time.time())
- if not alex_auth_qs.exists():
- AlexaAuthModel.objects.create(
- token=token,
- addTime=nowTime,
- updTime=nowTime,
- alexa_region=alexa_region,
- access_token=access_token,
- refresh_token=refresh_token,
- expiresTime=nowTime + 3200,
- skill_name=skill_name
- )
- else:
- alex_auth_qs.update(
- token=token,
- updTime=nowTime,
- alexa_region=alexa_region,
- access_token=access_token,
- refresh_token=refresh_token,
- expiresTime=nowTime + 3200,
- )
- # 更新业务服务器的token
- user_qs = UserModel.objects.filter(access_token=token).values('userID')
- if user_qs.exists():
- user_id = user_qs[0]['userID']
- if alexa_region == 'US':
- base_url = SERVER_PREFIX # SERVER_PREFIX, SERVER_PREFIX_TEST
- else:
- base_url = SERVER_PREFIX_EU
- url = '{}/alexaApi/appToApp/updateToken'.format(base_url)
- data = {
- 'user_id': user_id,
- 'access_token': access_token,
- 'refresh_token': refresh_token
- }
- r = requests.post(url=url, data=data, timeout=10)
- logger.info('请求更新token状态码: {}'.format(r.status_code))
- return JsonResponse({'code': 200, 'msg': 'success'})
- except Exception as e:
- logger.info('授权登录接口异常: error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
- return JsonResponse({'code': 500, 'msg': 'error'})
- # 向alexa事件网关发送更新设备操作V2接口
- def addOrUpdateV2(self, request_dict):
- logger = logging.getLogger('django')
- logger.info('--------添加/更新设备信息V2--------')
- region = request_dict.get("region", 'EN')
- data_list = request_dict.get("data_list", '')
- logger.info('data_list: {}'.format(data_list))
- data_list = json.loads(data_list) # 多通道设备才传 channel 键值对
- if not data_list:
- return JsonResponse({'code': 101, 'msg': 'Parameter error'})
- try:
- UID = data_list[0]['UID']
- userID = data_list[0]['userID']
- password = data_list[0]['password']
- password = CommonService().decode_pwd(password)
- # 获取alexa授权信息
- alexAuth = AlexaAuthModel.objects.filter(userID=userID). \
- values('expiresTime', 'access_token', 'refresh_token', 'alexa_region', 'skill_name')
- if not alexAuth.exists():
- logger.info('UID为 {} 的用户不存在'.format(UID))
- return JsonResponse({'code': 102, 'msg': 'not found user'})
- skill_name = alexAuth[0]['skill_name']
- expiresTime = alexAuth[0]['expiresTime']
- access_token = alexAuth[0]['access_token']
- refresh_token = alexAuth[0]['refresh_token']
- alexa_region = alexAuth[0]['alexa_region']
- if alexa_region not in ALEXA_EVENT_API.keys():
- logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
- return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
- # 更新alexa token
- now_time = int(time.time())
- if now_time > expiresTime:
- logger.info(refresh_token)
- res = self.getRefreshToken(refresh_token, skill_name)
- logger.info(res)
- if 'error' not in res:
- alexAuth.update(
- updTime=now_time,
- expiresTime=now_time + 3000,
- access_token=res['access_token'],
- refresh_token=res['refresh_token'],
- )
- access_token = res['access_token']
- else:
- logger.info('get refresh_token fail')
- return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
- # 添加rtsp记录
- channel = len(data_list) # 列表的元素个数即通道数量
- rtsp_url = tkObject(rank=1).encrypt(data=UID)
- uid_rtsp_qs = UidRtspModel.objects.filter(uid__contains=UID)
- if not uid_rtsp_qs.exists():
- # 创建UidRtsp数据
- if channel == 1:
- # 单通道设备
- UidRtspModel.objects.create(user_id=userID, uid=UID, nick=data_list[0]['uid_nick'], region=region,
- rtsp_url=rtsp_url, password=password, addTime=now_time,
- updTime=now_time)
- else:
- # 多通道设备
- bulk = []
- for data in data_list:
- uid = UID + '_' + str(data['channel']) # 多通道设备: uid_通道号
- uidRtsp = UidRtspModel(user_id=userID, uid=uid, nick=data['uid_nick'], region=region,
- rtsp_url=rtsp_url, password=password, addTime=now_time, updTime=now_time)
- bulk.append(uidRtsp)
- UidRtspModel.objects.bulk_create(bulk)
- else:
- # 更新UidRtsp数据
- count = len(uid_rtsp_qs)
- if count != channel:
- return JsonResponse({'code': 103, 'msg': '通道数不匹配'})
- if count == 1:
- uid_rtsp_qs.update(nick=data_list[0]['uid_nick'], region=region, password=password, user_id=userID)
- else:
- # 多通道设备
- for data in data_list:
- uid = UID + '_' + str(data['channel']) # 多通道设备: uid_通道号
- UidRtspModel.objects.filter(uid=uid).update(nick=data['uid_nick'], region=region,
- user_id=userID, password=password)
- api_uri = ALEXA_EVENT_API[alexa_region]
- messageId = str(uuid.uuid4()).strip()
- bearer_access_token = "Bearer {access_token}".format(access_token=access_token)
- headers = {"content-type": "application/json", "Authorization": bearer_access_token}
- endpoints = self.append_endpoint(data_list, channel)
- payload_json = {
- "event": {
- "header": {
- "namespace": "Alexa.Discovery",
- "name": "AddOrUpdateReport",
- "payloadVersion": "3",
- "messageId": messageId,
- },
- "payload": {
- "endpoints": endpoints,
- "scope": {
- "type": "BearerToken",
- "token": 'sdf',
- },
- },
- }
- }
- logger.info('--------Alexa AddOrUpdateReport请求: url:{},data:{}--------'.format(api_uri, payload_json))
- response = requests.post(api_uri, json=payload_json, headers=headers)
- logger.info('--------Alexa AddOrUpdateReport响应: {}--------'.format(response))
- return JsonResponse({'res': 'success'})
- except Exception as e:
- logger.info('--------添加/更新设备信息V2异常--------:error_line:{}, error_msg:{}'.
- format(e.__traceback__.tb_lineno, repr(e)))
- # 向alexa事件网关发送更新设备操作接口
- def addOrUpdateSwitch(self, request_dict):
- logger = logging.getLogger('django')
- logger.info('--------添加/更新插座信息--------')
- region = request_dict.get("region", 'US')
- nick_name = request_dict.get("nick_name", '')
- serial_number = request_dict.get("serial_number", '')
- user_id = request_dict.get("user_id", '')
- logger.info('region: {}, nick_name: {}, serial_number: {}, user_id: {}'.format(region, nick_name, serial_number,
- user_id))
- skill_name = 'loocam'
- if not all([nick_name, serial_number, user_id]):
- return JsonResponse({'code': 101, 'msg': 'Parameter error'})
- try:
- # 获取alexa授权信息
- alexAuth = AlexaAuthModel.objects.filter(userID=user_id, skill_name=skill_name). \
- values('expiresTime', 'access_token', 'refresh_token', 'alexa_region')
- if not alexAuth.exists():
- logger.info('serial_number {} 的用户不存在'.format(serial_number))
- return JsonResponse({'code': 102, 'msg': 'not found user'})
- expiresTime = alexAuth[0]['expiresTime']
- access_token = alexAuth[0]['access_token']
- refresh_token = alexAuth[0]['refresh_token']
- alexa_region = alexAuth[0]['alexa_region']
- if alexa_region not in ALEXA_EVENT_API.keys():
- logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
- return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
- # 更新alexa token
- now_time = int(time.time())
- if now_time > expiresTime:
- logger.info(refresh_token)
- res = self.getRefreshToken(refresh_token, skill_name)
- logger.info(res)
- if 'error' not in res:
- alexAuth.update(
- updTime=now_time,
- expiresTime=now_time + 3000,
- access_token=res['access_token'],
- refresh_token=res['refresh_token'],
- )
- access_token = res['access_token']
- else:
- logger.info('get refresh_token fail')
- return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
- # 添加rtsp记录
- switch_qs = SwitchModel.objects.filter(serial_number=serial_number, userID=user_id)
- if switch_qs.exists():
- switch_qs.update(nick=nick_name, updTime=now_time)
- else:
- data = {
- 'nick': nick_name,
- 'serial_number': serial_number,
- 'userID': user_id,
- 'region': region,
- 'addTime': now_time,
- 'updTime': now_time,
- }
- SwitchModel.objects.create(**data)
- api_uri = ALEXA_EVENT_API[alexa_region]
- messageId = str(uuid.uuid4()).strip()
- bearer_access_token = "Bearer {access_token}".format(access_token=access_token)
- headers = {"content-type": "application/json", "Authorization": bearer_access_token}
- endpoints = [{
- "endpointId": serial_number,
- "manufacturerName": skill_name,
- "friendlyName": nick_name,
- "description": 'Plug connected via {}'.format(skill_name),
- "displayCategories": ['SMARTPLUG'],
- "cookie": {},
- "capabilities": [
- {
- "type": 'AlexaInterface',
- "interface": 'Alexa.PowerController',
- "version": '3',
- "properties": {
- "supported": [
- {
- "name": "powerState"
- }
- ],
- "proactivelyReported": True,
- "retrievable": True
- },
- },
- {
- "type": 'AlexaInterface',
- "interface": 'Alexa',
- "version": '3'
- }
- ]
- }]
- payload_json = {
- "event": {
- "header": {
- "namespace": "Alexa.Discovery",
- "name": "AddOrUpdateReport",
- "payloadVersion": "3",
- "messageId": messageId,
- },
- "payload": {
- "endpoints": endpoints,
- "scope": {
- "type": "BearerToken",
- "token": 'sdf',
- },
- },
- }
- }
- response = requests.post(api_uri, json=payload_json, headers=headers)
- logger.info('--------Alexa AddOrUpdateReport响应: {}--------'.format(response))
- return JsonResponse({'res': 'success'})
- except Exception as e:
- logger.info('--------添加/更新插座信息异常--------:error_line:{}, error_msg:{}'.
- format(e.__traceback__.tb_lineno, repr(e)))
- return JsonResponse({'res': 'error'})
- # 向alexa事件网关发送插座状态操作接口
- def StateReport(self, request_dict):
- logger = logging.getLogger('django')
- logger.info('--------alexa智能插座状态上报--------')
- serial_number = request_dict.get("serial_number", None)
- access_token = request_dict.get("access_token", None)
- logger.info('请求参数: {}'.format(request_dict))
- response = ResObject()
- if not all([serial_number, access_token]):
- return response.json(10, res={'msg': 'Parameter error'})
- user_qs = UserModel.objects.filter(access_token=access_token)
- if not user_qs.exists():
- return response.json(10, res={'msg': '用户数据不存在'})
- user_id = user_qs.first().userID
- switch_qs = SwitchModel.objects.filter(serial_number=serial_number).values('region')
- if not switch_qs.exists():
- return response.json(10, res={'msg': '设备不存在'})
- try:
- region = switch_qs[0]['region']
- if region == 'EU':
- domain_name = SERVER_PREFIX_EU
- elif region == 'CN':
- domain_name = SERVER_PREFIX_TEST
- else:
- domain_name = SERVER_PREFIX
- auth_request_url = '{}/api/loocam/open/socket/getSocketState'.format(domain_name)
- requests_data = {'serial_number': serial_number, 'alexa_user_id': user_id}
- res = requests.post(url=auth_request_url, data=requests_data)
- res_json = res.json()
- logger.info('{}正式服务器响应: {}'.format(region, res_json))
- if res_json['result_code'] != 0:
- return response.json(10, res={'msg': 'error'})
- power_state = res_json['result']['power_state']
- if power_state:
- res = {'state': 'ON'}
- else:
- res = {'state': 'OFF'}
- return response.json(0, res=res)
- except Exception as e:
- logger.info('--------上传插座状态异常--------:error_line:{}, error_msg:{}'.
- format(e.__traceback__.tb_lineno, repr(e)))
- return response.json(10, res={'msg': '上报状态异常'})
- def append_endpoint(self, data_list, channel):
- # 组织 endpoints 数据
- endpoints = []
- for data in data_list:
- endpointId = data['UID'] if channel == 1 else data['UID'] + '_' + str(data['channel'])
- endpoint = {
- "endpointId": endpointId,
- "manufacturerName": "zosi smart",
- "modelName": "P1425-LE",
- "friendlyName": data['uid_nick'],
- "description": "Camera connected via zosi smart",
- "displayCategories": ["CAMERA"],
- "capabilities": [
- {
- "type": "AlexaInterface",
- "interface": "Alexa.CameraStreamController",
- "version": "3",
- "cameraStreamConfigurations": [
- {
- "protocols": ["RTSP"],
- "resolutions": [{"width": 1280, "height": 720}],
- "authorizationTypes": ["NONE"],
- "videoCodecs": ["H264"],
- "audioCodecs": ["ACC"],
- }
- ],
- }
- ],
- }
- endpoints.append(endpoint)
- return endpoints
- # 向alexa事件网关发送删除设备操作
- def delete(self, request_dict):
- UID = request_dict.get("UID", '')
- userID = request_dict.get("userID", '')
- logger = logging.getLogger('django')
- logger.info('--------删除设备--------')
- logger.info('userID: {}, UID: {}'.format(userID, UID))
- if not all([UID, userID]):
- return JsonResponse({'code': 111, 'msg': 'fail'})
- try:
- alexAuth = AlexaAuthModel.objects.filter(userID=userID). \
- values('expiresTime', 'refresh_token', 'access_token', 'alexa_region', 'skill_name')
- if not alexAuth.exists():
- logger.info('UID为 {} 的用户不存在'.format(UID))
- return JsonResponse({'code': 102, 'msg': 'not found user'})
- skill_name = alexAuth[0]['skill_name']
- expiresTime = alexAuth[0]['expiresTime']
- refresh_token = alexAuth[0]['refresh_token']
- access_token = alexAuth[0]['access_token']
- alexa_region = alexAuth[0]['alexa_region']
- if alexa_region not in ALEXA_EVENT_API.keys():
- logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
- return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
- now_time = int(time.time())
- if now_time > expiresTime:
- res = self.getRefreshToken(refresh_token, skill_name)
- if 'error' not in res:
- alexAuth.update(
- access_token=res['access_token'],
- refresh_token=res['refresh_token'],
- expiresTime=now_time + 300,
- updTime=now_time,
- )
- access_token = res['access_token']
- else:
- return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
- uidRtsp_qs = UidRtspModel.objects.filter(uid__contains=UID).values('uid')
- if not uidRtsp_qs.exists():
- return JsonResponse({'code': 103, 'msg': '不存在uidRtsp数据'})
- endpoints = []
- for uidRtsp in uidRtsp_qs:
- endpointId = {"endpointId": uidRtsp['uid']}
- endpoints.append(endpointId)
- headers = {
- "Authorization": "Bearer " + access_token,
- "Content-Type": "application/json;charset=UTF-8",
- "Cache-Control": "no-cache"
- }
- payload = {
- "event": {
- "header": {
- "namespace": "Alexa.Discovery",
- "name": "DeleteReport",
- "messageId": str(uuid.uuid4()),
- "payloadVersion": "3"
- },
- "payload": {
- "endpoints": endpoints,
- "scope": {
- "type": "BearerToken",
- "token": access_token
- }
- }
- }
- }
- api_uri = ALEXA_EVENT_API[alexa_region]
- response = requests.post(api_uri, json=payload, headers=headers)
- logger.info('--------Alexa DeleteReport响应: {}--------'.format(response))
- return JsonResponse({'res': 'success'})
- except Exception as e:
- logger.info('--------删除设备异常--------:error_line:{}, error_msg:{}'.
- format(e.__traceback__.tb_lineno, repr(e)))
- # 向alexa事件网关发送删除插座操作
- def deleteSwitch(self, request_dict):
- serial_number = request_dict.get("serial_number", '')
- logger = logging.getLogger('django')
- logger.info('--------删除插座--------')
- logger.info('serial_number: {}'.format(serial_number))
- if not all([serial_number]):
- return JsonResponse({'code': 111, 'msg': '参数异常'})
- skill_name = 'loocam'
- try:
- switch_qs = SwitchModel.objects.filter(serial_number=serial_number)
- if not switch_qs.exists():
- return JsonResponse({'code': 103, 'msg': '不存在socket数据'})
- userID = switch_qs[0].userID
- alexAuth = AlexaAuthModel.objects.filter(userID=userID, skill_name=skill_name). \
- values('expiresTime', 'refresh_token', 'access_token', 'alexa_region')
- if not alexAuth.exists():
- logger.info('序列号为 {} 的用户不存在'.format(serial_number))
- return JsonResponse({'code': 102, 'msg': 'not found user'})
- expiresTime = alexAuth[0]['expiresTime']
- refresh_token = alexAuth[0]['refresh_token']
- access_token = alexAuth[0]['access_token']
- alexa_region = alexAuth[0]['alexa_region']
- if alexa_region not in ALEXA_EVENT_API.keys():
- logger.info('alexa区域信息错误,alexa_region: {}'.format(alexa_region))
- return JsonResponse({'code': 102, 'msg': 'alexa_region error'})
- now_time = int(time.time())
- if now_time > expiresTime:
- res = self.getRefreshToken(refresh_token, skill_name)
- if 'error' not in res:
- alexAuth.update(
- access_token=res['access_token'],
- refresh_token=res['refresh_token'],
- expiresTime=now_time + 300,
- updTime=now_time,
- )
- access_token = res['access_token']
- else:
- return JsonResponse({'code': 102, 'msg': 'get refresh_token fail'})
- endpoints = []
- for switch in switch_qs:
- endpointId = {"endpointId": switch.serial_number}
- endpoints.append(endpointId)
- switch_qs.delete()
- headers = {
- "Authorization": "Bearer " + access_token,
- "Content-Type": "application/json;charset=UTF-8",
- "Cache-Control": "no-cache"
- }
- payload = {
- "event": {
- "header": {
- "namespace": "Alexa.Discovery",
- "name": "DeleteReport",
- "messageId": str(uuid.uuid4()),
- "payloadVersion": "3"
- },
- "payload": {
- "endpoints": endpoints,
- "scope": {
- "type": "BearerToken",
- "token": access_token
- }
- }
- }
- }
- api_uri = ALEXA_EVENT_API[alexa_region]
- response = requests.post(api_uri, json=payload, headers=headers)
- logger.info('--------Alexa DeleteReport响应: {}--------'.format(response))
- return JsonResponse({'res': 'success'})
- except Exception as e:
- logger.info('--------删除设备异常--------:error_line:{}, error_msg:{}'.
- format(e.__traceback__.tb_lineno, repr(e)))
- return JsonResponse({'res': 'error'})
- def getRefreshToken(self, refresh_token, skill_name):
- # 请求更新token
- logger = logging.getLogger('django')
- logger.info('--------{}请求更新token--------'.format(skill_name))
- if skill_name not in CLIENT_CONFIG.keys():
- # skill_name = 'Anlapus' # 应对UL测试,后期改回
- logger.info('--------技能名称错误,skill_name: {}--------'.format(skill_name))
- return JsonResponse({'code': 111, 'msg': 'skill_name error'})
- payload = {
- 'grant_type': 'refresh_token',
- 'refresh_token': refresh_token,
- 'client_id': CLIENT_CONFIG[skill_name]['client_id'],
- 'client_secret': CLIENT_CONFIG[skill_name]['client_secret'],
- }
- auth_request_url = 'https://api.amazon.com/auth/o2/token'
- headers = {
- 'content-type': "application/x-www-form-urlencoded",
- 'cache-control': "no-cache"
- }
- res = requests.post(auth_request_url, payload, headers)
- request_json = res.json()
- return request_json
|