DcFastCharge.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import re
  5. from decimal import Decimal
  6. from apps.web.constant import DeviceCmdCode, Const
  7. from apps.web.core.adapter.base import SmartBox
  8. from apps.web.core.exceptions import ServiceException
  9. from apps.web.core.networking import MessageSender
  10. from apps.web.device.models import Device
  11. from apps.web.user.models import ConsumeRecord
  12. class FastCharge(SmartBox):
  13. def __init__(self, device):
  14. super(FastCharge, self).__init__(device)
  15. def _check_package(self, package):
  16. """
  17. 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
  18. :param package:
  19. :return:
  20. """
  21. devConf = self.get_device_configs()
  22. coinElec = devConf.get('coinElec', 10) # 单位是0.1度
  23. coinTime = devConf.get('coinMin', 240)
  24. maxTotalTime = devConf.get('maxTotalTime', 0) or 720
  25. coins = float(package.get('coins'))
  26. elec = coins * coinElec * 0.1
  27. _time = min(coins * coinTime, maxTotalTime)
  28. return _time, elec, coins
  29. def disable_app_device(self, switch=True):
  30. # type:(bool) -> None
  31. otherConf = self.device.get('otherConf', {})
  32. otherConf['disableDevice'] = switch
  33. Device.objects.filter(devNo=self.device['devNo']).update(otherConf=otherConf)
  34. Device.invalid_device_cache(self.device['devNo'])
  35. def reverse_hex(self, data):
  36. # type:(str) -> str
  37. if not isinstance(data, str):
  38. raise TypeError
  39. return ''.join(list(reversed(re.findall(r'.{2}', data))))
  40. def encode_str(self, data, length=2, ratio=1.0, base=16):
  41. # type:(any,int,float,int) -> str
  42. if not isinstance(data, Decimal):
  43. data = Decimal(data).quantize(Decimal('0.00'))
  44. if not isinstance(length, str):
  45. length = str(length)
  46. if not isinstance(ratio, Decimal):
  47. ratio = Decimal(ratio)
  48. end = 'X' if base == 16 else 'd'
  49. encodeStr = '%.' + length + end
  50. encodeStr = encodeStr % (data * ratio)
  51. return encodeStr
  52. def decode_str(self, data, ratio=1.0, base=16, reverse=False):
  53. # type:(str,float,int,bool) -> str
  54. """
  55. ratio:比率单位转换
  56. """
  57. if not isinstance(data, str):
  58. data = str(data)
  59. if reverse:
  60. data = ''.join(list(reversed(re.findall(r'.{2}', data))))
  61. return '%.10g' % (int(data, base) * ratio)
  62. def decode_long_hex_to_list(self, data, split=2, ratio=1.0, base=16):
  63. # type:(str,int,float,int) -> list
  64. """
  65. return: list
  66. """
  67. if len(data) % split != 0:
  68. raise Exception('Invalid data')
  69. pattern = r'.{%s}' % split
  70. hex_list = re.findall(pattern, data)
  71. hex_list = map(lambda x: self.decode_str(x, ratio=ratio, base=base), hex_list)
  72. return hex_list
  73. def check_params_range(self, params, minData=None, maxData=None, desc=''):
  74. # type:(str,float,float,str) -> str
  75. """
  76. 检查参数,返回字符串参数
  77. """
  78. if params is None:
  79. raise ServiceException({'result': 2, 'description': u'参数错误.'})
  80. if not isinstance(params, Decimal):
  81. params = Decimal(params)
  82. if not minData and maxData:
  83. if not isinstance(maxData, Decimal):
  84. maxData = Decimal(maxData)
  85. if params <= maxData:
  86. return '%g' % params
  87. else:
  88. raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最大值为%g' % (desc, maxData)})
  89. if not maxData and minData:
  90. if not isinstance(minData, Decimal):
  91. minData = Decimal(minData)
  92. if minData <= params:
  93. return '%g' % params
  94. else:
  95. raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最小值为%g' % (desc, minData)})
  96. if not minData and not maxData:
  97. return '%g' % params
  98. else:
  99. if not isinstance(minData, Decimal):
  100. minData = Decimal(minData)
  101. if not isinstance(maxData, Decimal):
  102. maxData = Decimal(maxData)
  103. if minData <= params <= maxData:
  104. return '%g' % params
  105. else:
  106. raise ServiceException(
  107. {'result': 2, 'description': u'%s参数超出可选范围,可取范围为%g-%g' % (desc, minData, maxData)})
  108. def send_mqtt(self, funCode, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, order_id=None):
  109. """
  110. 发送mqtt 指令210 返回data
  111. """
  112. if not isinstance(funCode, str):
  113. funCode = str(funCode)
  114. if not isinstance(data, str):
  115. data = str(data)
  116. payload = {'IMEI': self.device['devNo'], 'funCode': funCode, 'data': data}
  117. if order_id:
  118. payload.update({'order_id': order_id})
  119. result = MessageSender.send(self.device, cmd, payload)
  120. if 'rst' in result and result['rst'] != 0:
  121. if result['rst'] == -1:
  122. raise ServiceException(
  123. {'result': 2, 'description': u'该设备正在玩命找网络,请您稍候再试', 'rst': -1})
  124. elif result['rst'] == 1:
  125. raise ServiceException(
  126. {'result': 2, 'description': u'该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  127. else:
  128. if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]:
  129. return
  130. if 'order_id' in result or 'order_info' in result:
  131. return result
  132. else:
  133. return result.get('data', '')
  134. @staticmethod
  135. def port_is_busy(port_dict):
  136. if not port_dict:
  137. return False
  138. if 'billingType' not in port_dict:
  139. return False
  140. if 'status' not in port_dict:
  141. return False
  142. if 'coins' not in port_dict:
  143. return False
  144. if port_dict['billingType'] not in ['time', 'elec']:
  145. return False
  146. if port_dict['billingType'] == 'time':
  147. if 'needTime' not in port_dict:
  148. return False
  149. else:
  150. if 'needElec' not in port_dict:
  151. return False
  152. if port_dict['status'] == Const.DEV_WORK_STATUS_WORKING:
  153. return True
  154. else:
  155. return False
  156. def do_update_configs(self, updateDict):
  157. dev = Device.objects.get(devNo=self.device.devNo)
  158. deviceConfigs = dev.otherConf.get('deviceConfigs', {})
  159. deviceConfigs.update(updateDict)
  160. dev.otherConf['deviceConfigs'] = deviceConfigs
  161. dev.save()
  162. Device.invalid_device_cache(self.device.devNo)
  163. def get_device_configs(self):
  164. dev = Device.get_dev(self.device.devNo)
  165. deviceConfigs = dev.get('otherConf', {}).get('deviceConfigs', {})
  166. return deviceConfigs
  167. def start_device_realiable(self, order):
  168. # type:(ConsumeRecord)->dict
  169. package = order.package
  170. coins = package.get('coins', 0)
  171. deviceType = '03'
  172. port = order.used_port
  173. userType = '01'
  174. userNum = '{:0>16s}'.format(order.orderNo)
  175. sequanceNo = '{:0>16s}'.format(order.orderNo) + datetime.datetime.now().strftime('%Y%m%d%H%M%S')
  176. balance = self.encode_str(coins, length=8, ratio=100.0)
  177. chargeType = '00' # 00 为立即充电 01为 预约充电
  178. featureStr = 'FF'
  179. self.get_consumption_rules()
  180. return {}
  181. def get_dev_setting(self):
  182. deviceConfigs = self.get_device_configs()
  183. if not deviceConfigs:
  184. pass
  185. packages = [{'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '00:00'},
  186. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '03:00'},
  187. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '06:00'},
  188. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '09:00'},
  189. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '12:00'},
  190. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '15:00'},
  191. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '18:00'},
  192. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '21:00'}]
  193. return {'package': packages}
  194. def set_device_function_param(self, request, lastSetConf):
  195. print request, lastSetConf
  196. def get_consumption_rules(self):
  197. packages = [
  198. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '00:00'},
  199. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '03:00'},
  200. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '06:00'},
  201. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '09:00'},
  202. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '12:00'},
  203. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '15:00'},
  204. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '18:00'},
  205. {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '21:00'},
  206. ]
  207. data = ''
  208. count = 0
  209. for item in packages:
  210. count += 1
  211. hour, min = item['startTime'].split(':')
  212. data += self.encode_str(hour)
  213. data += self.encode_str(min)
  214. if count % 2 == 0:
  215. data += self.encode_str(item['unitPrice'])
  216. data += self.encode_str(item['serviceFee'])
  217. data += self.encode_str(item['parkingFee'])
  218. return data
  219. def stop(self, port=None):
  220. data = {
  221. 'port': int(port),
  222. 'remote_type': 0,
  223. }
  224. result = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  225. data)