import time from threading import Thread import traceback import uuid import logging import requests from requests.exceptions import RequestException from rest_framework.exceptions import APIException, ParseError from django.conf import settings from apps.third.errors import SP_REQUEST_ERROR from apps.third.models import Tlog from apps.utils.tools import print_roundtrip, ranstr from apps.third.tapis import spapis from django.utils.timezone import now from apps.utils.tools import singleton from django.core.cache import cache requests.packages.urllib3.disable_warnings() myLogger = logging.getLogger('log') @singleton class SpClient: """ 音响接口 """ def __init__(self) -> None: self.sp_enabled = getattr(settings, 'SP_ENABLED', False) if self.sp_enabled: self.username = settings.SP_USERNAME self.password = settings.SP_PASSWORD self.headers = {"Connection": "close"} self.isGetingToken = False self.log = {} self._get_token() def _get_token(self): self.isGetingToken = True json_data = { "user": { "email": self.username, "password": self.password } } is_ok, res = self.request(**spapis['user_login'], json=json_data, raise_exception=False) if is_ok == 'success': cache.set('sp_token', res['user']['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.sp_enabled: raise ParseError('音响对接未启用') self.headers['Authorization'] = 'Bearer ' + cache.get('sp_token', '') self.log = {"requested_at": now(), "id": uuid.uuid4(), "path": url, "method": method, "params": params, "body": json, "target": "speaker", "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) try: r = getattr(requests, method)('{}{}'.format(settings.SP_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 'code' in ret and ret['code'] not in ['0', '100', '00000', '1000', 0, 100, 1000]: detail = '音响错误:{}'.format(str(ret.get('msg', ''))) err_detail = dict(detail=detail, code='sp_'+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 else: self.handle_log(result='error', response=ret) except RequestException: print(traceback.format_exc()) self.handle_log(result='error', errors=traceback.format_exc()) if raise_exception: raise APIException(**SP_REQUEST_ERROR) return 'error', SP_REQUEST_ERROR def speak(self, path: str, sns: list, v_num: int, v_p: int=0): """播放报警声 Args: path (str): 资源本地地址或文本内容 sns (list): 喇叭sn队列 v_num (int): 播放次数 """ uri = path is_text = False if '/' not in path: is_text = True if is_text: v_p_voice = "xiaoyan" if v_p != 0: v_p_voice = "xiaofeng" uri = f"{settings.SP_TTS_URL}/tts_xf.single?text={path}&voice_name={v_p_voice}&speed=50&volume=100&origin={settings.SP_TTS_URL}" elif not uri.startswith('http'): uri = settings.BASE_URL_IN + path urls = [] while v_num > 0: urls.append({ "name": "alarm.mp3", "uri": uri }) v_num = v_num - 1 json = { "sns": sns, "type": "req", "name": "songs_queue_append", "params": { "tid": ranstr(6), "vol": 100, "urls": urls } } self.request(**spapis['send_to_device'], json=json) return """ Args: text (str): 文本内容 sns (list): 喇叭sn队列 v_num (int): 播放次数 """ if text: uri = f"{settings.SP_TTS_URL}/tts_xf.single?text=有车辆上磅35.5千克,请刷卡。&voice_name=xiaoyan&speed=50&volume=100&origin={settings.SP_TTS_URL}" urls = [] while v_num > 0: urls.append({ "name": "alarm.mp3", "uri": uri }) v_num = v_num - 1 json = { "sns": sns, "type": "req", "name": "songs_queue_append", "params": { "tid": ranstr(6), "vol": 100, "urls": urls } } self.request(**spapis['send_to_device'], json=json) return 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() spClient = SpClient()