views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import logging
  4. import uuid
  5. import simplejson as json
  6. from typing import TYPE_CHECKING
  7. from apilib.utils_json import JsonResponse
  8. from apps.web.agent.models import Agent
  9. from apps.web.api.exceptions import ApiParameterError, ApiAuthDeviceException, ApiNoDeviceException, ApiDeviceTypeError
  10. from apps.web.api.utils import api_call, api_exception_response, api_ok_response, api_error_response, \
  11. api_ok_response_v2, deprecated_api_error_response
  12. from apps.web.constant import DeviceCmdCode, ErrorCode, MQTT_TIMEOUT
  13. from apps.web.core.db import paginate
  14. from apps.web.core.exceptions import ServiceException
  15. from apps.web.core.helpers import ActionDeviceBuilder
  16. from apps.web.core.networking import MessageSender
  17. from apps.web.dealer.models import Dealer
  18. from apps.web.dealer.utils import get_devices_by_dealer
  19. from apps.web.device.models import Device
  20. from apps.web.api.models import APIStartDeviceRecord
  21. from apps.web.utils import error_tolerate
  22. if TYPE_CHECKING:
  23. from django.core.handlers.wsgi import WSGIRequest
  24. from apps.web.device.models import DeviceDict
  25. logger = logging.getLogger(__name__)
  26. @api_call(logger = logger, nil = api_exception_response())
  27. def deviceOnlineStatus(request, dealer):
  28. # type: (WSGIRequest, Dealer)->JsonResponse
  29. payload = json.loads(request.body) if request.body else {}
  30. if not payload:
  31. raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
  32. if 'deviceCode' not in payload:
  33. raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
  34. device = Device.get_dev_by_logicalCode(payload['deviceCode'])
  35. if not device.is_authorized_to_dealer(str(dealer.id)):
  36. raise ApiAuthDeviceException()
  37. result = MessageSender.send(device = device, cmd = DeviceCmdCode.GET_DEVINFO, payload = {'IMEI': device['devNo']})
  38. if result['rst'] != 0:
  39. return api_ok_response(payload = {'online': 0, 'signal': 0})
  40. else:
  41. return api_ok_response(payload = {'online': 1, 'signal': int(result.get('signal', 0))})
  42. @api_call(logger = logger, nil = api_exception_response())
  43. def apiStartDevice(request, dealer):
  44. # type: (WSGIRequest, Dealer)->JsonResponse
  45. payload = json.loads(request.body) if request.body else {}
  46. if not payload:
  47. raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
  48. if 'deviceCode' not in payload:
  49. raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
  50. device = Device.get_dev_by_logicalCode(payload['deviceCode']) # type: DeviceDict
  51. if not device:
  52. raise ApiNoDeviceException()
  53. if not device.is_authorized_to_dealer(str(dealer.id)):
  54. raise ApiAuthDeviceException()
  55. # 整理额外参数
  56. attachParas = payload.get('attachParas', {})
  57. if 'channel' in payload:
  58. channel = payload.get('channel', 'unknown')
  59. else:
  60. channel = attachParas.pop('channel', '')
  61. if 'extOrderNo' in payload:
  62. orderNo = payload.get('extOrderNo')
  63. else:
  64. orderNo = attachParas.pop('extOrderNo', str(uuid.uuid4()))
  65. attachParas['extOrderNo'] = orderNo
  66. if 'userId' in payload:
  67. user_id = payload.get('userId', '')
  68. else:
  69. user_id = attachParas.pop('userId', '')
  70. if 'createTime' in payload:
  71. create_time = payload.get('createTime')
  72. else:
  73. create_time = attachParas.pop('createTime', '')
  74. if 'coins' not in payload and 'package' not in payload:
  75. raise ApiParameterError(errmsg = u'coins和package参数不能同时为空')
  76. if 'coins' in payload:
  77. package = {
  78. 'coins': payload['coins']
  79. }
  80. else:
  81. if isinstance(payload['package'], str):
  82. package = device['washConfig'].get(payload['package'])
  83. elif isinstance(payload['package'], dict):
  84. package = payload['package']
  85. else:
  86. raise ApiParameterError(errmsg = u'package必须为字符串或者json字典')
  87. notify_url = payload.get('notify_url', '')
  88. record = APIStartDeviceRecord(orderNo = orderNo,
  89. deviceCode = payload['deviceCode'],
  90. userId = user_id,
  91. createTime = create_time,
  92. package = package,
  93. notifyUrl = notify_url,
  94. apiConf = getattr(dealer, 'api_conf'),
  95. channel = channel,
  96. devNo = device['devNo'],
  97. ownerId = device['ownerId'],
  98. attachParas = attachParas)
  99. record.save()
  100. err_code = ErrorCode.EXCEPTION
  101. err_msg = u'系统错误'
  102. try:
  103. if 'coins' in payload:
  104. # 兼容以前代码, 走的是同步接口
  105. result = MessageSender.net_pay(device = device, coins = int(package['coins']),
  106. timeout = MQTT_TIMEOUT.START_DEVICE)
  107. else:
  108. smartBox = ActionDeviceBuilder.create_action_device(device)
  109. result = smartBox.start_from_api(record = record)
  110. if result and 'rst' in result:
  111. # 这个是同步接口
  112. err_code = result.get('rst')
  113. err_msg = str(result.get('desc', ''))
  114. return api_ok_response(payload = {'status': err_code, 'desc': err_msg})
  115. else:
  116. # 异步接口没有值返回
  117. return api_ok_response(payload = {'status': 0, 'desc': u'成功下发启动设备命令'})
  118. except ServiceException as e:
  119. logger.error('start device({}) failed error(code={},msg={})'.format(device['devNo'], e.result.get('result'),
  120. e.result.get('description')))
  121. err_code = e.result.get('result')
  122. err_msg = str(e.result.get('description'))
  123. return api_ok_response(payload = {'status': err_code, 'desc': err_msg})
  124. except Exception as e:
  125. logger.exception('start device({}) failed error={}'.format(device['devNo'], e))
  126. err_code = ErrorCode.EXCEPTION
  127. err_msg = str(e)
  128. return api_error_response(errcode = ErrorCode.API_EXCEPTION, errmsg = u'系统错误')
  129. finally:
  130. try:
  131. record.errCode = err_code
  132. record.errMsg = err_msg
  133. record.save()
  134. except Exception as e:
  135. logger.exception(e)
  136. @api_call(logger = logger, nil = api_exception_response())
  137. def apiGetDevicePackageList(request, dealer):
  138. # type: (WSGIRequest, Dealer)->JsonResponse
  139. payload = json.loads(request.body) if request.body else {}
  140. if not payload:
  141. raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
  142. if 'deviceCode' not in payload:
  143. raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
  144. device = Device.get_dev_by_logicalCode(payload['deviceCode'])
  145. if not device.is_authorized_to_dealer(str(dealer.id)):
  146. raise ApiAuthDeviceException()
  147. # 返回errcode, errmsg, packages. 其他为兼容
  148. response_dict = {
  149. 'errcode': ErrorCode.SUCCESS,
  150. 'errmsg': 'SUCCESS',
  151. 'result': 1,
  152. 'payload': device['washConfig'],
  153. 'packages': device['washConfig'],
  154. 'description': ''
  155. }
  156. return JsonResponse(response_dict)
  157. @api_call(logger = logger, nil = api_exception_response())
  158. def order(request, dealer):
  159. # type: (WSGIRequest, Dealer)->JsonResponse
  160. return api_ok_response(payload = {}, description = u'成功查询订单')
  161. @api_call(logger = logger, nil = api_exception_response())
  162. def getDeviceListByDealer(request, dealer):
  163. # type:(WSGIRequest, Dealer)->JsonResponse
  164. pageIndex = 1
  165. pageSize = 10
  166. payload = json.loads(request.body) if request.body else {}
  167. if not payload:
  168. pageIndex = int(request.GET.get('pageIndex', 1))
  169. pageSize = int(request.GET.get('pageSize', 10))
  170. else:
  171. pageIndex = int(payload.get('pageIndex', 1))
  172. pageSize = int(payload.get('pageSize', 10))
  173. def public_only(device):
  174. return {k: v for k, v in device.iteritems() if k not in Device.protected_fields()}
  175. devices = [public_only(_) for _ in get_devices_by_dealer(dealer)]
  176. return api_ok_response(payload = {'devices': paginate(devices, pageIndex, pageSize)})
  177. @api_call(logger = logger, nil = api_exception_response())
  178. def apiGetChargerInfo(request, dealer):
  179. # type: (WSGIRequest)->JsonResponse
  180. payload = json.loads(request.body) if request.body else {}
  181. if not payload:
  182. raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
  183. if 'deviceCode' not in payload:
  184. raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
  185. device = Device.get_dev_by_logicalCode(payload['deviceCode'])
  186. if device is None:
  187. raise ApiNoDeviceException()
  188. if not device.is_authorized_to_dealer(str(dealer.id)):
  189. raise ApiAuthDeviceException()
  190. data = {}
  191. ctrInfo = Device.get_dev_control_cache(device['devNo'])
  192. if ctrInfo.has_key('elecValue'):
  193. data.update({'elec': ctrInfo['elecValue']})
  194. else:
  195. try:
  196. box = ActionDeviceBuilder.create_action_device(device)
  197. valueDict = box.get_port_elec_from_dev()
  198. data.update({'elec': valueDict})
  199. except Exception, e:
  200. data.update({'elec': {}})
  201. if ctrInfo.has_key('temperatureValue'):
  202. data.update({'temperature': ctrInfo['temperatureValue']})
  203. else:
  204. try:
  205. box = ActionDeviceBuilder.create_action_device(device)
  206. valueDict = box.get_port_temperature_from_dev()
  207. data.update({'temperature': valueDict})
  208. except Exception, e:
  209. data.update({'temperature': {}})
  210. if ctrInfo.has_key('isYangan'):
  211. data.update({'smokeDetected': ctrInfo['isYangan']})
  212. else:
  213. data.update({'smokeDetected': False})
  214. return api_ok_response_v2(**data)
  215. @api_call(logger = logger, nil = api_exception_response())
  216. def apiGetDevStatus(request, dealer):
  217. # type: (WSGIRequest)->JsonResponse
  218. payload = json.loads(request.body) if request.body else {}
  219. if not payload:
  220. raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
  221. if 'deviceCode' not in payload:
  222. raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
  223. device = Device.get_dev_by_logicalCode(payload['deviceCode']) # type: DeviceDict
  224. if device is None:
  225. raise ApiNoDeviceException()
  226. if not device.is_authorized_to_dealer(str(dealer.id)):
  227. raise ApiAuthDeviceException()
  228. data = {'status': device.status}
  229. try:
  230. box = device.deviceAdapter
  231. portStatus = box.get_port_status_from_dev()
  232. if portStatus is not None:
  233. data.update({'portStatus': portStatus})
  234. return api_ok_response(payload = data)
  235. except NotImplementedError:
  236. raise ApiDeviceTypeError(errmsg = u'未找到端口查询函数,请注意是否注册了正确的设备类型')
  237. @api_call(logger = logger, nil = api_exception_response())
  238. def apiStopDevice(request, dealer):
  239. # type: (WSGIRequest)->JsonResponse
  240. payload = json.loads(request.body) if request.body else {}
  241. if not payload:
  242. raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
  243. if 'deviceCode' not in payload:
  244. raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
  245. device = Device.get_dev_by_logicalCode(payload['deviceCode']) # type: DeviceDict
  246. if device is None:
  247. raise ApiNoDeviceException()
  248. if not device.is_authorized_to_dealer(str(dealer.id)):
  249. raise ApiAuthDeviceException()
  250. box = ActionDeviceBuilder.create_action_device(device)
  251. oper_result = box.stop()
  252. Device.invalid_device_control_cache(device['devNo'])
  253. return api_ok_response(payload = {'status': oper_result['rst']})
  254. @error_tolerate(logger = logger, nil = deprecated_api_error_response(description = u'系统错误'))
  255. def apiGetPackage(request):
  256. # type: (WSGIRequest)->JsonResponse
  257. sign = request.POST.get('sign', None)
  258. channel = request.POST.get('channel', None)
  259. logicalCode = request.POST.get('deviceCode', None)
  260. if None in [sign, channel, logicalCode]:
  261. return JsonResponse({'code': '00000001', 'msg': u'缺少必须的参数'})
  262. # 检查签名是否存在
  263. if not sign:
  264. return JsonResponse({'code': '00000002', 'msg': u'签名不能为空'})
  265. try:
  266. agent = Agent.objects.get(agentSign = sign)
  267. except Exception, e:
  268. logger.exception('get agent error=%s' % e)
  269. return JsonResponse({'code': '00000003', 'msg': u'错误的签名'})
  270. dev = Device.get_dev_by_logicalCode(logicalCode)
  271. dealer = Dealer.objects.get(id = dev['ownerId'])
  272. if str(agent.id) != dealer['agentId']:
  273. return JsonResponse({'code': '00000005', 'msg': u'设备编号和商户ID不匹配'})
  274. if dev is None:
  275. return JsonResponse({'code': '00000004', 'msg': u'未找到对应的设备'})
  276. return JsonResponse({'code': '00000000', 'msg': '', 'data': dev['washConfig']})