weifule_time.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python
  3. import copy
  4. import datetime
  5. import time
  6. from apps.web.constant import DeviceCmdCode, Const, FAULT_CODE, ErrorCode, MQTT_TIMEOUT
  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, MyUser, Card
  12. from apilib.utils_datetime import to_datetime
  13. from apilib.utils_AES import EncryptDate
  14. cardKey = 'FR4e1OFCnDdrYA7u'
  15. class ChargingWEIFULEBox(SmartBox):
  16. def __init__(self, device):
  17. super(ChargingWEIFULEBox, self).__init__(device)
  18. def translate_funcode(self, fun_code):
  19. fun_codeDict = {
  20. '01': u'查询所有端口状态',
  21. '02': u'查询端口详细信息',
  22. '03': u'上报投币充电事件',
  23. '04': u'上报刷卡事件',
  24. '05': u'上报充电结束事件',
  25. '06': u'远程停止充电',
  26. '07': u'远程启动充电',
  27. '08': u'查询投币总额',
  28. '09': u'清除投币总数',
  29. '0A': u'查询订单信息',
  30. }
  31. return fun_codeDict.get(fun_code, '')
  32. def translate_event_cmdcode(self, cmdCode):
  33. cmdDict = {
  34. }
  35. return cmdDict.get(cmdCode, '')
  36. def test(self, coins):
  37. data = {'fun_code':0x07,'order_id':'1111','coins':coins,'port':1,'time':60}
  38. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  39. {'IMEI': self._device['devNo'], 'data': data})
  40. return devInfo
  41. def check_feedback_result(self,devInfo):
  42. if not devInfo.has_key('rst'):
  43. raise ServiceException({'result': 2, 'description': u'报文异常'})
  44. if devInfo['rst'] == -1:
  45. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  46. if devInfo['rst'] == 1:
  47. raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
  48. if devInfo['rst'] == 2:
  49. raise ServiceException({'result': 2, 'description': u'端口被禁用'})
  50. if devInfo['rst'] == 3:
  51. raise ServiceException({'result': 2, 'description': u'端口计量器故障'})
  52. if devInfo['rst'] == 4:
  53. raise ServiceException({'result': 2, 'description': u'设备订单已达上限'})
  54. if devInfo['rst'] == 5:
  55. raise ServiceException({'result': 2, 'description': u'设备正在自检'})
  56. # result = devInfo['data']['result']
  57. # if result == 0:
  58. # return
  59. # else:#等待设备的错误码进行细化
  60. # raise ServiceException({'result': 2, 'description': u'充电桩返回了错误,请您重试看看能否解决问题'})
  61. def start_device(self, package, openId, attachParas):
  62. if attachParas is None:
  63. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  64. if not attachParas.has_key('chargeIndex'):
  65. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  66. port = int(attachParas['chargeIndex'])
  67. unit = package.get('unit', u'分钟')
  68. needTime = None
  69. coins = int(float(package['coins'])*100)#单位为分
  70. onPoints = attachParas.get('onPoints')
  71. if onPoints: # 远程上分
  72. self.stop_charging_port(port)
  73. order_no = ConsumeRecord.make_no()
  74. else:
  75. order_no = str(attachParas.get("orderNo"))
  76. if unit == u'秒':
  77. if int(package['time']) < 60:
  78. raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
  79. needTime = int(float(package['time']))
  80. data = {'fun_code':0x07,'order_id':order_no,'coins':coins,'port':port,'time':needTime}
  81. elif unit == u'分钟':
  82. needTime = int(package['time'])*60
  83. data = {'fun_code':0x07,'order_id':order_no,'coins':coins,'port':port,'time':needTime}
  84. elif unit == u'小时':
  85. needTime = int(float(package['time']) * 60 * 60)
  86. data = {'fun_code':0x07,'order_id':order_no,'coins':coins,'port':port,'time':needTime}
  87. elif unit == u'天':
  88. needTime = int(float(package['time']) * 60 * 60 * 24)
  89. data = {'fun_code':0x07,'order_id':order_no,'coins':coins,'port':port,'time':needTime}
  90. elif unit == u'度':
  91. raise ServiceException({'result': 2, 'description': u'只支持按时间付费'})
  92. else:
  93. needTime = int(package['time'])
  94. data = {'fun_code':0x07,'order_id':order_no,'coins':coins,'port':port,'time':needTime}
  95. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  96. {'IMEI': self._device['devNo'], 'data': data}, timeout = MQTT_TIMEOUT.START_DEVICE)
  97. self.check_feedback_result(devInfo)
  98. data = devInfo['data']
  99. if devInfo['rst'] == 0: # 成功
  100. devInfo['consumeOrderNo'] = data['order']['id']
  101. newValue = {
  102. str(port): {
  103. 'status': Const.DEV_WORK_STATUS_WORKING,
  104. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  105. }
  106. }
  107. else:#TODO result的枚举列出原因
  108. raise ServiceException({'result': 2, 'description': u'充电桩响应异常,请您稍后再试哦'})
  109. if needTime:
  110. finishedTime = int(time.time()) + needTime
  111. devInfo['needTime'] = needTime/60
  112. newValue.update({'finishedTime': finishedTime})
  113. Device.update_dev_control_cache(self._device['devNo'], newValue)
  114. devInfo['finished_time'] = finishedTime
  115. devInfo['consumeOrderNo'] = order_no
  116. return devInfo
  117. def analyze_event_data(self, data):
  118. if data['fun_code'] == '34':#如果是结束事件,需要把reason翻译出来
  119. descDict = {
  120. '1':u'开始充电,但是没有接充电器',
  121. '2':u'充电过程中,插座脱落',
  122. '3':u'用户按下关闭按钮关闭',
  123. '4':u'用户刷卡结束充电',
  124. '5':u'远程结束充电',
  125. '6':u'充电端口故障,为了安全主动关闭',
  126. '7':u'订购的时间使用完毕',
  127. '8':u'订购的电量使用完毕',
  128. '9':u'本端口功率过载,主动关闭',
  129. '10':u'整机功率过载,主动关闭',
  130. '11':u'其他异常导致的关闭'
  131. }
  132. order = data['order']
  133. order['reason'] = descDict.get(str(order['closeType']),u'')
  134. data['order'] = order
  135. return data
  136. def get_dev_consume_count(self):
  137. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  138. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x08}})
  139. self.check_feedback_result(devInfo)
  140. data = devInfo['data']
  141. return {'cardFee': data['total_card']/100.0, 'coinFee': data['total_coin']/100.0}#单位为分
  142. def get_many_port_info(self,portList):
  143. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  144. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x12}})
  145. self.check_feedback_result(devInfo)
  146. resultDict = {}
  147. for port,data in devInfo['data']['details'].items():
  148. if port not in portList:
  149. continue
  150. result = {'index':port}
  151. result['status'] = self.__translate_status_from_str(data['status'])
  152. curOrder = None
  153. for order in data['orders']:
  154. if order['status'] == 'running':
  155. curOrder = order
  156. break
  157. if curOrder:
  158. if curOrder['order_type'] == 'apps_start':
  159. result['consumeType'] = 'mobile'
  160. try:
  161. rcd = ConsumeRecord.objects.get(orderNo = curOrder['id'])
  162. if u'虚拟卡' in rcd.remarks:
  163. result['consumeType'] = 'mobile_vcard'
  164. except Exception,e:
  165. pass
  166. elif curOrder['order_type'] == 'coin_start':
  167. result['consumeType'] = 'coin'
  168. elif curOrder['order_type'] == 'card_start':
  169. result['consumeType'] = 'card'
  170. if curOrder.has_key('amount_time'):
  171. result['needTime'] = round(curOrder['amount_time']/60.0,1)
  172. if curOrder.has_key('time'):
  173. result['duration'] = round(curOrder['time']/60.0,1)
  174. result['usedTime'] = round(curOrder['time']/60.0,1)
  175. if curOrder.has_key('left_time'):
  176. result['leftTime'] = round(curOrder['left_time']/60.0,1)
  177. if curOrder.has_key('execute_time'):
  178. result['startTime'] = datetime.datetime.fromtimestamp(int(curOrder['execute_time'])).strftime('%m-%d %H:%M:%S')
  179. if curOrder.has_key('id') and (curOrder['order_type'] not in ['coin_start','card_charge']) :#card_charge
  180. try:
  181. rcd = ConsumeRecord.objects.get(orderNo = curOrder['id'])
  182. result['openId'] = rcd['openId']
  183. result['coins'] = float(str(rcd['coin']))#都用coins
  184. result['money'] = float(str(rcd['money']))
  185. result['orderNo'] = str(curOrder['id'])
  186. user = MyUser.objects(openId=result['openId']).first()
  187. if user:
  188. result['nickName'] = user.nickname
  189. except Exception,e:#IC卡,如果没有绑定,不会有consumeRcd,应该直接从订单中拿数据
  190. result['coins'] = float(order['coins']/100.0)
  191. result['money'] = float(order['coins']/100.0)
  192. pass
  193. resultDict[port] = result
  194. return resultDict
  195. def get_port_info(self, line):
  196. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  197. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x02, 'port': int(line)}})
  198. self.check_feedback_result(devInfo)
  199. #找出当前正在执行的订单
  200. result = {}
  201. data = devInfo['data']
  202. result['status'] = self.__translate_status_from_str(data['status'])
  203. curOrder = None
  204. for order in data['orders']:
  205. if order['status'] == 'running':
  206. curOrder = order
  207. break
  208. if curOrder:
  209. if curOrder['order_type'] == 'apps_start':
  210. result['consumeType'] = 'mobile'
  211. try:
  212. rcd = ConsumeRecord.objects.get(orderNo = curOrder['id'])
  213. if u'虚拟卡' in rcd.remarks:
  214. result['consumeType'] = 'mobile_vcard'
  215. except Exception,e:
  216. pass
  217. elif curOrder['order_type'] == 'coin_start':
  218. result['consumeType'] = 'coin'
  219. elif curOrder['order_type'] == 'card_start':
  220. result['consumeType'] = 'card'
  221. if curOrder.has_key('amount_time'):
  222. result['needTime'] = round(curOrder['amount_time']/60.0,1)
  223. if curOrder.has_key('time'):
  224. result['duration'] = round(curOrder['time']/60.0,1)
  225. result['usedTime'] = round(curOrder['time']/60.0,1)
  226. if curOrder.has_key('left_time'):
  227. result['leftTime'] = round(curOrder['left_time']/60.0,1)
  228. if curOrder.has_key('execute_time'):
  229. result['startTime'] = datetime.datetime.fromtimestamp(int(curOrder['execute_time'])).strftime('%m-%d %H:%M:%S')
  230. if curOrder.has_key('card_no'):
  231. result['cardNo'] = str(int(curOrder['card_no'],16))
  232. if curOrder.has_key('id') and (curOrder['order_type'] not in ['coin_start','card_charge']) :#card_charge
  233. try:
  234. rcd = ConsumeRecord.objects.get(orderNo = curOrder['id'])
  235. result['openId'] = rcd['openId']
  236. result['coins'] = float(str(rcd['coin']))#都用coins
  237. result['money'] = float(str(rcd['money']))
  238. result['orderNo'] = str(curOrder['id'])
  239. except Exception,e:
  240. pass
  241. return result
  242. def __translate_status_from_str(self,status):
  243. dictConf = {
  244. 'idle':Const.DEV_WORK_STATUS_IDLE,
  245. 'busy':Const.DEV_WORK_STATUS_WORKING,
  246. 'forbid':Const.DEV_WORK_STATUS_FORBIDDEN,
  247. 'fault':Const.DEV_WORK_STATUS_FAULT,
  248. 'running':Const.DEV_WORK_STATUS_WORKING
  249. }
  250. return dictConf.get(status,Const.DEV_WORK_STATUS_IDLE)
  251. # 访问设备,获取设备端口信息
  252. def get_port_status_from_dev(self):
  253. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  254. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x01}})
  255. self.check_feedback_result(devInfo)
  256. data = devInfo['data']
  257. result = {}
  258. portNum = data.get('total',10)
  259. ii = 0
  260. while ii < portNum:
  261. ii += 1
  262. result[str(ii)] = {'status':self.__translate_status_from_str(data['status'].get(str(ii)))}
  263. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  264. Device.update_dev_control_cache(self._device['devNo'],
  265. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  266. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  267. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  268. for strPort, info in result.items():
  269. if ctrInfo.has_key(strPort):
  270. ctrInfo[strPort].update({'status': info['status']})
  271. else:
  272. ctrInfo[strPort] = info
  273. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  274. return result
  275. def get_port_status(self, force = False):
  276. if force:
  277. return self.get_port_status_from_dev()
  278. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  279. if not ctrInfo.has_key('allPorts'):
  280. self.get_port_status_from_dev()
  281. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  282. allPorts = ctrInfo.get('allPorts', 10)
  283. statusDict = {}
  284. for ii in range(allPorts):
  285. tempDict = ctrInfo.get(str(ii + 1), {})
  286. if tempDict.has_key('status'):
  287. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  288. elif tempDict.has_key('isStart'):
  289. if tempDict['isStart']:
  290. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  291. else:
  292. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  293. else:
  294. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  295. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  296. Device.update_dev_control_cache(self._device['devNo'],
  297. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  298. return statusDict
  299. def lock_unlock_port(self, port, lock = True):
  300. portInfo = self.get_port_info(port)
  301. if portInfo and portInfo['status'] == Const.DEV_WORK_STATUS_WORKING and lock:
  302. raise ServiceException({'result': 2, 'description': u'端口正忙,请先关闭端口后,再禁止端口'})
  303. typeStr = 'deactive' if lock else 'active'
  304. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  305. {'IMEI': self._device['devNo'], 'data': {'port':int(port),'type':typeStr,'fun_code':0x0D}})
  306. self.check_feedback_result(devInfo)
  307. if devInfo['rst'] == 0:
  308. if lock:
  309. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  310. else:
  311. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  312. else:
  313. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  314. def active_deactive_port(self, port, active):
  315. if active:
  316. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  317. return self.stop_charging_port(port)
  318. #停止该端口下的所有任务
  319. def stop_charging_port(self, port):
  320. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  321. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x06, 'port': port}})
  322. self.check_feedback_result(devInfo)
  323. if devInfo['rst'] == 0:
  324. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  325. return True if devInfo['rst'] == 0 else False
  326. def get_order(self,order_no):
  327. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  328. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x0A, 'order_id': order_no}})
  329. self.check_feedback_result(devInfo)
  330. curOrder = devInfo['data'].get('order',None)
  331. result = {}
  332. if not curOrder.has_key('order_type'):#有可能没有订单,应该返回空
  333. return result
  334. result['status'] = curOrder['status']
  335. if curOrder['order_type'] == 'apps_start':
  336. result['consumeType'] = 'mobile'
  337. try:
  338. rcd = ConsumeRecord.objects.get(orderNo = curOrder['id'])
  339. if u'虚拟卡' in rcd.remarks:
  340. result['consumeType'] = 'mobile_vcard'
  341. except Exception,e:
  342. pass
  343. elif curOrder['order_type'] == 'coin_start':
  344. result['consumeType'] = 'coin'
  345. elif curOrder['order_type'] == 'card_start':
  346. result['consumeType'] = 'card'
  347. if curOrder.has_key('amount_time'):
  348. result['needTime'] = round(curOrder['amount_time']/60.0,1)
  349. if curOrder.has_key('time'):
  350. result['duration'] = round(curOrder['time']/60.0,1)
  351. result['usedTime'] = round(curOrder['time']/60.0,1)
  352. if curOrder.has_key('left_time'):
  353. result['leftTime'] = round(curOrder['left_time']/60.0,1)
  354. if curOrder.has_key('execute_time'):
  355. result['startTime'] = datetime.datetime.fromtimestamp(int(curOrder['execute_time'])).strftime('%m-%d %H:%M:%S')
  356. if curOrder.has_key('card_no'):
  357. result['cardNo'] = str(int(curOrder['card_no'],16))
  358. if curOrder.has_key('id') and (curOrder['order_type'] not in ['coin_start','card_charge']) :#card_charge
  359. try:
  360. rcd = ConsumeRecord.objects.get(orderNo = curOrder['id'])
  361. result['openId'] = rcd['openId']
  362. result['coins'] = float(str(rcd['coin']))#都用coins
  363. result['money'] = float(str(rcd['money']))
  364. result['orderNo'] = str(curOrder['id'])
  365. except Exception,e:
  366. return None
  367. return result
  368. def response_card_balance(self, cardNo,balance,result):
  369. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  370. {'IMEI': self._device['devNo'], 'data': {'fun_code':35,'card_no':cardNo,'balance':int(100*float(balance)),'result':result}})
  371. self.check_feedback_result(devInfo)
  372. # 获取设备配置参数
  373. def get_dev_setting(self):
  374. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  375. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x0C}})
  376. self.check_feedback_result(devInfo)
  377. result = devInfo['data']
  378. packageTime = []
  379. for name,conf in result['package'].items():
  380. if name == 'TIME':
  381. for k,v in conf.items():
  382. packageTime.append({'price':int(k)/100,'time':v/60})#单位从秒转为分钟
  383. result['package_time'] = packageTime
  384. defaultVolume = 0
  385. volumeList = []
  386. for k,v in result['volume'].items():
  387. if k == 'default':
  388. defaultVolume = v
  389. else:
  390. tempList = k.split('-')
  391. volumeList.append({'start':tempList[0],'end':tempList[1],'volume':v})
  392. result.pop('volume')
  393. result['volume'] = defaultVolume
  394. result['volume_list'] = volumeList
  395. result['once_card'] = result['once_card'] / 100.0
  396. result['once_coin'] = result['once_coin'] / 100.0
  397. state = self.get_dev_consume_count()
  398. result.update(state)
  399. return result
  400. # 获取设备配置参数
  401. def set_dev_setting(self, setConf):
  402. #如果是卡密码,直接进行修改
  403. if setConf.has_key('card_pwd'):
  404. return self.set_card_pwd(setConf['card_pwd'])
  405. #检查数据
  406. if not (int(setConf['volume']) >= 0 and int(setConf['volume']) <= 7):
  407. raise ServiceException({'result': 2, 'description': u'音量必须大于等于0,小于等于7'})
  408. #时间套餐不能为空
  409. if setConf.has_key('package_time') and len(setConf['package_time']) == 0:
  410. raise ServiceException({'result': 2, 'description': u'按时间计费的套餐不能为空'})
  411. volumeDict = {'default':int(setConf['volume'])}
  412. for vl in setConf['volume_list']:
  413. startTime = to_datetime('2020-01-01 %s:00' % vl['start'])
  414. endTime = to_datetime('2020-01-01 %s:00' % vl['end'])
  415. if endTime <= startTime:
  416. raise ServiceException({'result': 2, 'description': u'结束时间一定要大于起始时间。比如起始时间为07:00,结束时间为23:59'})
  417. volumeDict['%s-%s' % (vl['start'],vl['end'])] = int(vl['volume'])
  418. setConf.pop('volume')
  419. setConf.pop('volume_list')
  420. setConf['volume'] = volumeDict
  421. setConf['once_card'] = int(float(setConf['once_card'])*100)
  422. setConf['once_coin'] = int(float(setConf['once_coin'])*100)
  423. setConf.update({'fun_code':0x0B})
  424. packageElec,packageTime = {},{}
  425. isHaveOneCoinForElec,isHaveOneCoinForTime = False,False
  426. for pConf in setConf['package_time']:
  427. if pConf['price'] == 1:
  428. isHaveOneCoinForTime = True
  429. packageTime[str(int(float(pConf['price'])*100))] = int(float(pConf['time'])*60)
  430. if setConf['chrmt']=='TIME' and not isHaveOneCoinForTime:
  431. raise ServiceException({'result': 2, 'description': u'刷卡投币收费模式中,至少需要包含1元的使用套餐'})
  432. if len(packageTime) != len(setConf['package_time']) :
  433. raise ServiceException({'result': 2, 'description': u'套餐价格不允许出现重复'})
  434. setConf.pop('package_time')
  435. setConf['package'] = {'TIME':packageTime}
  436. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  437. {'IMEI': self._device['devNo'], 'data': setConf})
  438. self.check_feedback_result(devInfo)
  439. def ack_event(self,orderNo,funCode):
  440. devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
  441. {'IMEI': self._device['devNo'], 'data': {'fun_code':funCode,'order_id':orderNo}})
  442. self.check_feedback_result(devInfo)
  443. def clear_dev_feecount(self):
  444. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  445. {'IMEI': self._device['devNo'], 'data': {'fun_code':0x09,'total_coin':True,'total_card':True}})
  446. self.check_feedback_result(devInfo)
  447. def response_card_charge_result(self,cardNo,result):
  448. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SERVER_ASYNC,
  449. {'IMEI': self._device['devNo'], 'data': {'fun_code':37,'card_no':cardNo,'result':result}})
  450. def reboot_device(self):
  451. data = {'fun_code':0x0B,'reset_mcu':True}
  452. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  453. {'IMEI': self._device['devNo'], 'data': data})
  454. MessageSender.async_send(self.device, DeviceCmdCode.SET_DEVINFO,
  455. {'IMEI': self._device['devNo'], 'restart': True})
  456. def set_device_function(self, request, lastSetConf):
  457. if request.POST.has_key('clearSum'):
  458. self.clear_dev_feecount()
  459. elif request.POST.has_key('reboot'):
  460. self.reboot_device()
  461. def set_device_function_param(self, request, lastSetConf):
  462. newConf = copy.deepcopy(request.POST)
  463. newConf.pop('logicalCode', None)
  464. self.set_dev_setting(newConf)
  465. def get_card_pwd(self):
  466. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  467. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x11}})
  468. self.check_feedback_result(devInfo)
  469. result = devInfo['data']
  470. enObj = EncryptDate(cardKey)
  471. cardPwd = enObj.decrypt(result['card_pwd'])
  472. if not cardPwd:
  473. cardPwd = ''
  474. return {'card_pwd':cardPwd}
  475. def translante_card_no(self,hexCardNo):
  476. return int(hexCardNo,16)
  477. def check_pwd(self,pwd):
  478. if len(pwd) != 6:
  479. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  480. for char in pwd:
  481. if not (char>='0' and char<='9'):
  482. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  483. return
  484. def set_card_pwd(self,pwd):
  485. self.check_pwd(pwd)
  486. enObj = EncryptDate(cardKey)
  487. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  488. {'IMEI': self._device['devNo'], 'data': {'fun_code':0x0B,'card_pwd':enObj.encrypt(pwd)}})
  489. self.check_feedback_result(devInfo)
  490. def set_card_mode(self,setConf):
  491. cardMode = int(setConf.get('card_mode'))
  492. valueDict = {'fun_code':0x10}
  493. if cardMode == 0:
  494. valueDict.update({'mode':cardMode})
  495. elif cardMode == 1:#格式化为离线卡
  496. self.check_pwd(setConf['new_pwd'])
  497. newPwd = setConf['new_pwd']
  498. if not str(setConf['balance']).isdigit():
  499. raise ServiceException({'result': 2, 'description': u'余额必须是数字'})
  500. balance = int(setConf['balance'])
  501. if not (balance >=0 and balance <= 5000):
  502. raise ServiceException({'result': 2, 'description': u'余额必须在0和5000元之间'})
  503. balance = balance * 10#硬件模块记录的单位是角
  504. enObj = EncryptDate(cardKey)
  505. valueDict.update({'mode':1,'new_pwd':enObj.encrypt(str(newPwd)),'balance':balance})
  506. elif cardMode == 2:
  507. self.check_pwd(setConf['old_pwd'])
  508. self.check_pwd(setConf['new_pwd'])
  509. newPwd = setConf['new_pwd']
  510. oldPwd = setConf['old_pwd']
  511. enObj = EncryptDate(cardKey)
  512. valueDict.update({'mode':2,'old_pwd':enObj.encrypt(str(oldPwd)),'new_pwd':enObj.encrypt(str(newPwd))})
  513. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  514. {'IMEI': self._device['devNo'], 'data': valueDict})
  515. self.check_feedback_result(devInfo)
  516. def get_card_mode(self):
  517. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  518. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x11}})
  519. self.check_feedback_result(devInfo)
  520. cardMode = devInfo['data']['card_mode']
  521. return {'card_mode':cardMode}
  522. def check_alarm(self,alarm):
  523. if alarm.faultCode == FAULT_CODE.MCU_REBOOT:
  524. return u'此告警,建议您多观察,如果比较频繁不停上报单台设备的告警,可能会运行不稳定。需要您联系技术支持确认。'
  525. elif alarm.faultCode == FAULT_CODE.COUNTER_FAULT:
  526. portInfo = self.get_port_info(alarm.portNo)
  527. if portInfo['status'] == Const.DEV_WORK_STATUS_FAULT:
  528. return u'此端口目前已经为故障状态,继电器可能运行不稳定,建议您联系技术支持,以确认设备运行情况。'
  529. else:
  530. return u'端口状态检查正常,继电器或存偶尔无法获取数据。暂不影响使用。'
  531. elif alarm.faultCode == FAULT_CODE.RELAY_FAULT:
  532. return u'无法进行远程诊断,建议您到现场,直接插上插座,然后检查是否不用付款,就能够充电。如果是的,就属于继电器粘连。'
  533. elif alarm.faultCode == FAULT_CODE.DEV_OVERLOAD:
  534. return u'整机功率最大限定为7500瓦,接入的负载超过此负载,为了安全,将强行关闭所有充电端口。'
  535. elif alarm.faultCode == FAULT_CODE.COPY_CARD:
  536. return u'出现一模一样的卡,可能是用户复制了另外一张离线卡,然后使用,会给您造成经济上的损失,建议冻结。'
  537. return ''
  538. def get_part_info(self):
  539. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  540. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x05}})
  541. self.check_feedback_result(devInfo)
  542. partInfo = devInfo['data']
  543. result = {}
  544. nameDesc = {'networkBoard':u'网络板','chargeBoard':u'充电板','cardBoard':u'刷卡板'}
  545. for k,v in partInfo.items():
  546. if k not in nameDesc:
  547. continue
  548. result[nameDesc.get(k)] = {'SN':v}
  549. return result
  550. def recharge_card(self, cardNo, money, orderNo=None):
  551. hex_cardNo = hex(int(cardNo))[2::].replace('L', '').upper()
  552. result = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SERVER_ASYNC,
  553. {'IMEI': self.device['devNo'],
  554. 'data': {'fun_code': 37, 'result': 1, 'card_no': hex_cardNo,
  555. 'charge': int(money * 100),
  556. 'order_id': orderNo}})
  557. # 返回验证
  558. self.check_feedback_result(result)
  559. card = Card.objects.filter(cardNo=cardNo,dealerId=self.device.ownerId).first()
  560. balance = card.balance + money
  561. return {
  562. 'result': ErrorCode.SUCCESS,
  563. 'description': ''
  564. }, balance
  565. def get_customize_score_unit(self):
  566. return u'元'
  567. def get_customize_package_unit(self):
  568. chrmt = self.device['otherConf'].get('chrmt')
  569. if not chrmt:
  570. chrmt = self.get_dev_setting().get('chrmt')
  571. # 按时间计费
  572. if chrmt == 'TIME' or chrmt == 'POWER':
  573. return u'分钟'
  574. # 按电量计费
  575. elif chrmt == 'ELEC':
  576. return u'度'
  577. return u'元'
  578. def start_customize_point(self,pointNum,openId,port):
  579. unit = self.get_customize_package_unit()
  580. package = {'name':'customizePoint','price':pointNum,'coins':pointNum,'unit':unit,'time':999}
  581. attachParas = {'chargeIndex':port,'onPoints':True}
  582. return self.start_device(package, openId, attachParas)