123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import logging
- import uuid
- import simplejson as json
- from typing import TYPE_CHECKING
- from apilib.utils_json import JsonResponse
- from apps.web.agent.models import Agent
- from apps.web.api.exceptions import ApiParameterError, ApiAuthDeviceException, ApiNoDeviceException, ApiDeviceTypeError
- from apps.web.api.utils import api_call, api_exception_response, api_ok_response, api_error_response, \
- api_ok_response_v2, deprecated_api_error_response
- from apps.web.constant import DeviceCmdCode, ErrorCode, MQTT_TIMEOUT
- from apps.web.core.db import paginate
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.helpers import ActionDeviceBuilder
- from apps.web.core.networking import MessageSender
- from apps.web.dealer.models import Dealer
- from apps.web.dealer.utils import get_devices_by_dealer
- from apps.web.device.models import Device
- from apps.web.api.models import APIStartDeviceRecord
- from apps.web.utils import error_tolerate
- if TYPE_CHECKING:
- from django.core.handlers.wsgi import WSGIRequest
- from apps.web.device.models import DeviceDict
- logger = logging.getLogger(__name__)
- @api_call(logger = logger, nil = api_exception_response())
- def deviceOnlineStatus(request, dealer):
- # type: (WSGIRequest, Dealer)->JsonResponse
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
- if 'deviceCode' not in payload:
- raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
- device = Device.get_dev_by_logicalCode(payload['deviceCode'])
- if not device.is_authorized_to_dealer(str(dealer.id)):
- raise ApiAuthDeviceException()
- result = MessageSender.send(device = device, cmd = DeviceCmdCode.GET_DEVINFO, payload = {'IMEI': device['devNo']})
- if result['rst'] != 0:
- return api_ok_response(payload = {'online': 0, 'signal': 0})
- else:
- return api_ok_response(payload = {'online': 1, 'signal': int(result.get('signal', 0))})
- @api_call(logger = logger, nil = api_exception_response())
- def apiStartDevice(request, dealer):
- # type: (WSGIRequest, Dealer)->JsonResponse
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
- if 'deviceCode' not in payload:
- raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
- device = Device.get_dev_by_logicalCode(payload['deviceCode']) # type: DeviceDict
- if not device:
- raise ApiNoDeviceException()
- if not device.is_authorized_to_dealer(str(dealer.id)):
- raise ApiAuthDeviceException()
- # 整理额外参数
- attachParas = payload.get('attachParas', {})
- if 'channel' in payload:
- channel = payload.get('channel', 'unknown')
- else:
- channel = attachParas.pop('channel', '')
- if 'extOrderNo' in payload:
- orderNo = payload.get('extOrderNo')
- else:
- orderNo = attachParas.pop('extOrderNo', str(uuid.uuid4()))
- attachParas['extOrderNo'] = orderNo
- if 'userId' in payload:
- user_id = payload.get('userId', '')
- else:
- user_id = attachParas.pop('userId', '')
- if 'createTime' in payload:
- create_time = payload.get('createTime')
- else:
- create_time = attachParas.pop('createTime', '')
- if 'coins' not in payload and 'package' not in payload:
- raise ApiParameterError(errmsg = u'coins和package参数不能同时为空')
- if 'coins' in payload:
- package = {
- 'coins': payload['coins']
- }
- else:
- if isinstance(payload['package'], str):
- package = device['washConfig'].get(payload['package'])
- elif isinstance(payload['package'], dict):
- package = payload['package']
- else:
- raise ApiParameterError(errmsg = u'package必须为字符串或者json字典')
- notify_url = payload.get('notify_url', '')
- record = APIStartDeviceRecord(orderNo = orderNo,
- deviceCode = payload['deviceCode'],
- userId = user_id,
- createTime = create_time,
- package = package,
- notifyUrl = notify_url,
- apiConf = getattr(dealer, 'api_conf'),
- channel = channel,
- devNo = device['devNo'],
- ownerId = device['ownerId'],
- attachParas = attachParas)
- record.save()
- err_code = ErrorCode.EXCEPTION
- err_msg = u'系统错误'
- try:
- if 'coins' in payload:
- # 兼容以前代码, 走的是同步接口
- result = MessageSender.net_pay(device = device, coins = int(package['coins']),
- timeout = MQTT_TIMEOUT.START_DEVICE)
- else:
- smartBox = ActionDeviceBuilder.create_action_device(device)
- result = smartBox.start_from_api(record = record)
- if result and 'rst' in result:
- # 这个是同步接口
- err_code = result.get('rst')
- err_msg = str(result.get('desc', ''))
- return api_ok_response(payload = {'status': err_code, 'desc': err_msg})
- else:
- # 异步接口没有值返回
- return api_ok_response(payload = {'status': 0, 'desc': u'成功下发启动设备命令'})
- except ServiceException as e:
- logger.error('start device({}) failed error(code={},msg={})'.format(device['devNo'], e.result.get('result'),
- e.result.get('description')))
- err_code = e.result.get('result')
- err_msg = str(e.result.get('description'))
- return api_ok_response(payload = {'status': err_code, 'desc': err_msg})
- except Exception as e:
- logger.exception('start device({}) failed error={}'.format(device['devNo'], e))
- err_code = ErrorCode.EXCEPTION
- err_msg = str(e)
- return api_error_response(errcode = ErrorCode.API_EXCEPTION, errmsg = u'系统错误')
- finally:
- try:
- record.errCode = err_code
- record.errMsg = err_msg
- record.save()
- except Exception as e:
- logger.exception(e)
- @api_call(logger = logger, nil = api_exception_response())
- def apiGetDevicePackageList(request, dealer):
- # type: (WSGIRequest, Dealer)->JsonResponse
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
- if 'deviceCode' not in payload:
- raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
- device = Device.get_dev_by_logicalCode(payload['deviceCode'])
- if not device.is_authorized_to_dealer(str(dealer.id)):
- raise ApiAuthDeviceException()
- # 返回errcode, errmsg, packages. 其他为兼容
- response_dict = {
- 'errcode': ErrorCode.SUCCESS,
- 'errmsg': 'SUCCESS',
- 'result': 1,
- 'payload': device['washConfig'],
- 'packages': device['washConfig'],
- 'description': ''
- }
- return JsonResponse(response_dict)
- @api_call(logger = logger, nil = api_exception_response())
- def order(request, dealer):
- # type: (WSGIRequest, Dealer)->JsonResponse
- return api_ok_response(payload = {}, description = u'成功查询订单')
- @api_call(logger = logger, nil = api_exception_response())
- def getDeviceListByDealer(request, dealer):
- # type:(WSGIRequest, Dealer)->JsonResponse
- pageIndex = 1
- pageSize = 10
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- pageIndex = int(request.GET.get('pageIndex', 1))
- pageSize = int(request.GET.get('pageSize', 10))
- else:
- pageIndex = int(payload.get('pageIndex', 1))
- pageSize = int(payload.get('pageSize', 10))
- def public_only(device):
- return {k: v for k, v in device.iteritems() if k not in Device.protected_fields()}
- devices = [public_only(_) for _ in get_devices_by_dealer(dealer)]
- return api_ok_response(payload = {'devices': paginate(devices, pageIndex, pageSize)})
- @api_call(logger = logger, nil = api_exception_response())
- def apiGetChargerInfo(request, dealer):
- # type: (WSGIRequest)->JsonResponse
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
- if 'deviceCode' not in payload:
- raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
- device = Device.get_dev_by_logicalCode(payload['deviceCode'])
- if device is None:
- raise ApiNoDeviceException()
- if not device.is_authorized_to_dealer(str(dealer.id)):
- raise ApiAuthDeviceException()
- data = {}
- ctrInfo = Device.get_dev_control_cache(device['devNo'])
- if ctrInfo.has_key('elecValue'):
- data.update({'elec': ctrInfo['elecValue']})
- else:
- try:
- box = ActionDeviceBuilder.create_action_device(device)
- valueDict = box.get_port_elec_from_dev()
- data.update({'elec': valueDict})
- except Exception, e:
- data.update({'elec': {}})
- if ctrInfo.has_key('temperatureValue'):
- data.update({'temperature': ctrInfo['temperatureValue']})
- else:
- try:
- box = ActionDeviceBuilder.create_action_device(device)
- valueDict = box.get_port_temperature_from_dev()
- data.update({'temperature': valueDict})
- except Exception, e:
- data.update({'temperature': {}})
- if ctrInfo.has_key('isYangan'):
- data.update({'smokeDetected': ctrInfo['isYangan']})
- else:
- data.update({'smokeDetected': False})
- return api_ok_response_v2(**data)
- @api_call(logger = logger, nil = api_exception_response())
- def apiGetDevStatus(request, dealer):
- # type: (WSGIRequest)->JsonResponse
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
- if 'deviceCode' not in payload:
- raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
- device = Device.get_dev_by_logicalCode(payload['deviceCode']) # type: DeviceDict
- if device is None:
- raise ApiNoDeviceException()
- if not device.is_authorized_to_dealer(str(dealer.id)):
- raise ApiAuthDeviceException()
- data = {'status': device.status}
- try:
- box = device.deviceAdapter
- portStatus = box.get_port_status_from_dev()
- if portStatus is not None:
- data.update({'portStatus': portStatus})
- return api_ok_response(payload = data)
- except NotImplementedError:
- raise ApiDeviceTypeError(errmsg = u'未找到端口查询函数,请注意是否注册了正确的设备类型')
- @api_call(logger = logger, nil = api_exception_response())
- def apiStopDevice(request, dealer):
- # type: (WSGIRequest)->JsonResponse
- payload = json.loads(request.body) if request.body else {}
- if not payload:
- raise ApiParameterError(errmsg = u'传递为空或payload格式有误,请传JSON格式')
- if 'deviceCode' not in payload:
- raise ApiParameterError(errmsg = u'必须传递deviceCode参数')
- device = Device.get_dev_by_logicalCode(payload['deviceCode']) # type: DeviceDict
- if device is None:
- raise ApiNoDeviceException()
- if not device.is_authorized_to_dealer(str(dealer.id)):
- raise ApiAuthDeviceException()
- box = ActionDeviceBuilder.create_action_device(device)
- oper_result = box.stop()
- Device.invalid_device_control_cache(device['devNo'])
- return api_ok_response(payload = {'status': oper_result['rst']})
- @error_tolerate(logger = logger, nil = deprecated_api_error_response(description = u'系统错误'))
- def apiGetPackage(request):
- # type: (WSGIRequest)->JsonResponse
- sign = request.POST.get('sign', None)
- channel = request.POST.get('channel', None)
- logicalCode = request.POST.get('deviceCode', None)
- if None in [sign, channel, logicalCode]:
- return JsonResponse({'code': '00000001', 'msg': u'缺少必须的参数'})
- # 检查签名是否存在
- if not sign:
- return JsonResponse({'code': '00000002', 'msg': u'签名不能为空'})
- try:
- agent = Agent.objects.get(agentSign = sign)
- except Exception, e:
- logger.exception('get agent error=%s' % e)
- return JsonResponse({'code': '00000003', 'msg': u'错误的签名'})
- dev = Device.get_dev_by_logicalCode(logicalCode)
- dealer = Dealer.objects.get(id = dev['ownerId'])
- if str(agent.id) != dealer['agentId']:
- return JsonResponse({'code': '00000005', 'msg': u'设备编号和商户ID不匹配'})
- if dev is None:
- return JsonResponse({'code': '00000004', 'msg': u'未找到对应的设备'})
- return JsonResponse({'code': '00000000', 'msg': '', 'data': dev['washConfig']})
|