chaochen.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. # -*- coding: utf-8 -*-
  2. # 超辰充电桩业务流程描述
  3. # 整个业务比较简单,算是经典的充电桩业务对接,但有以下问题需要注意
  4. # 1. 超辰的通信方式为485通信,485通信中有一项为通信地址,即板位地址,属于硬件开关
  5. # 2. 该板位地址经多次与该技术方沟通,确定了以下的规则:
  6. # 2.1 有端口操作指令的时候,该板位地址使用端口号来代替,如操作10号端口开启,则板位地址数据为0A
  7. # 2.2 无端口指令操作的时候,该板位地址 固定为01,例如参数获取以及参数设置等不涉及端口的指令
  8. # 3. 超辰充电桩指令目前看起来是不完备的,缺少了一条 查看当前充电方式的指令,原因如下
  9. # 3.1 充电模式分为 电量计费 以及 时间计费, 该模式可远程切换
  10. # 3.2 切换模式后,主板结束的时候上报的指令数据含义不一样,电量模式下需要使用 EA 指令结算退款 时间模式下 使用C9指令退款
  11. # 3.2 由于服务器无法知道此时主板到底处于什么计费方式下,所以只能以经销商上一次设置的 充电模式为准,主板默认出厂 模式为时间模式
  12. # 3.3 所以服务器结束的时候需要读取当前的充电方式 默认也为时间模式
  13. # 4. 超辰寄过来打样的主板 是10路,实际有2 路 4 路 以及 10路的,2路4路没有实际测试,但是姚总坚持认为三个主板协议一样。
  14. import logging
  15. import random
  16. import time
  17. from apilib.utils_datetime import timestamp_to_dt
  18. from apps.web.common.transaction import UserConsumeSubType
  19. from apps.web.constant import DeviceCmdCode, MQTT_TIMEOUT, Const
  20. from apps.web.core.adapter.base import SmartBox
  21. from apps.web.core.exceptions import ServiceException
  22. from apps.web.core.networking import MessageSender
  23. from apps.web.device.models import Device
  24. from apps.web.user.models import ConsumeRecord, MyUser
  25. logger = logging.getLogger(__name__)
  26. class ChaoChenBox(SmartBox):
  27. DEFAULT_CHARGE_TYPE = "time"
  28. DEFAULT_FULL_STOP = 0
  29. def _send_data(self, funCode, content, cmd=None, timeout=MQTT_TIMEOUT.NORMAL):
  30. if cmd is None:
  31. cmd = DeviceCmdCode.OPERATE_DEV_SYNC
  32. result = MessageSender.send(
  33. device=self.device,
  34. cmd=cmd,
  35. payload={
  36. "IMEI": self._device["devNo"],
  37. "funCode": funCode,
  38. "data": content
  39. },
  40. timeout=timeout
  41. )
  42. if result.get("rst") == -1:
  43. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请稍候再试'})
  44. elif result.get("rst") == 1:
  45. raise ServiceException({'result': 2, 'description': u'充电桩串口故障,请稍后再试'})
  46. elif result.get("rst") == 0:
  47. # data = result.get("data", "")
  48. # if data[10: 12] != "01":
  49. # raise ServiceException({'result': 2, 'description': u'执行命令失败,请稍后再试'})
  50. return result
  51. else:
  52. raise ServiceException({'result': 2, 'description': u'系统错误'})
  53. def _start_device(self, portStr, orderNo, money, leftMoney):
  54. if not leftMoney:
  55. leftMoney = 0x000000
  56. orderHex = "{:016X}".format(int(orderNo))
  57. moneyHex = "{:06X}".format(int(float(money) * 100))
  58. leftMoneyHex = "{:06X}".format(int(float(leftMoney) * 100))
  59. result = self._send_data(
  60. funCode="{:02X}A7".format(int(portStr)),
  61. content=orderHex + moneyHex + leftMoneyHex
  62. )
  63. return result
  64. def _stop(self, portStr):
  65. result = self._send_data(
  66. funCode="{:02X}D6".format(int(portStr)),
  67. content="01"
  68. )
  69. return result
  70. @property
  71. def poweroffTime(self):
  72. """ TODO 设置不起作用"""
  73. result = self._send_data("01B2", "01")
  74. return int(result["data"][12: 20], 16)
  75. @property
  76. def curElec(self):
  77. result = self._send_data("01B3", "01")
  78. return int(result['data'][-4:-2], 16) / 1000.0
  79. @property
  80. def standElec(self):
  81. result = self._send_data("01C3", "01")
  82. data = result["data"]
  83. m = int(data[14: 16], 16) / 10.0
  84. s = int(data[12: 14], 16) / 10.0
  85. return {
  86. "maxElec": m,
  87. "standElec": s
  88. }
  89. @property
  90. def totalCoinConsume(self):
  91. result = self._send_data("01C1", "01")
  92. return int(result["data"][12: 18], 16) / 100.0
  93. @property
  94. def totalCardConsume(self):
  95. result = self._send_data("01C2", "01")
  96. return int(result["data"][12: 18], 16) / 100.0
  97. @property
  98. def emptyTime(self):
  99. result = self._send_data("01E6", "01")
  100. return int(result["data"][12: 16], 16)
  101. @property
  102. def emptyPower(self):
  103. result = self._send_data("01E4", "01")
  104. return int(result["data"][12: 16], 16)
  105. # ------这三个暂时设置为只读属性------------------
  106. @poweroffTime.setter
  107. def poweroffTime(self, value):
  108. self._send_data("01B1", "{:08X}".format(int(value)))
  109. @emptyPower.setter
  110. def emptyPower(self, value):
  111. self._send_data("01E3", "{:04X}".format(int(value)))
  112. @emptyTime.setter
  113. def emptyTime(self, value):
  114. self._send_data("01E5", "{:04X}".format(int(value)))
  115. @standElec.setter
  116. def standElec(self, value):
  117. standElec = value['standElec']
  118. maxElec = value['maxElec']
  119. dataHex = "{:0>2X}{:0>2X}".format(int(float(standElec) * 10), int(float(maxElec) * 10))
  120. self._send_data("01A4", dataHex)
  121. # ----------浮充功率不需要 主板回复也不对---------
  122. @property
  123. def fuChongPower(self):
  124. # TODO 未按协议格式回执报文
  125. # result = self._send_data("01D2", "01")
  126. # data = result["data"]
  127. # return int(data[12: 16], 16)
  128. return
  129. @fuChongPower.setter
  130. def fuChongPower(self, value):
  131. # self._send_data("01D1", "{:04X}".format(int(value)))
  132. pass
  133. # --------------------------------------------
  134. def _set_recover(self):
  135. self._send_data("01F5", "01")
  136. def _set_clear_line_time(self):
  137. raise ServiceException({"result": "2", "description": u"暂不支持此项功能"})
  138. def _set_reboot(self):
  139. self._send_data("01D7", "01")
  140. @property
  141. def chargeType(self):
  142. """ 该主板没有获取充电模式的 接口"""
  143. return self.device.get("otherConf", dict()).get("chargeType", self.DEFAULT_CHARGE_TYPE)
  144. @chargeType.setter
  145. def chargeType(self, value):
  146. if value == "time":
  147. result = self._send_data("01E8", "00")
  148. else:
  149. result = self._send_data("01E8", "01")
  150. resultCode = result['data'][10:12]
  151. if resultCode == "00":
  152. raise ServiceException({"result": 2, "description": u"切换模式失败,请等待所有充电订单结束<{}>".format(resultCode)})
  153. if resultCode == "02":
  154. raise ServiceException({"result": 2, "description": u"切换模式失败,<{}>".format(resultCode)})
  155. otherConf = self.device.get("otherConf", dict())
  156. otherConf['chargeType'] = value
  157. Device.objects.filter(devNo=self.device.devNo).update(otherConf=otherConf)
  158. Device.invalid_device_cache(self.device.devNo)
  159. @property
  160. def stepPower(self):
  161. result = self._send_data("01F2", "01")
  162. data = result['data'][12: -2]
  163. step = dict()
  164. for _index in range(0, 24, 6):
  165. # step.append(
  166. # {"power": int(data[_index: _index+4], 16), "discount": int(data[_index+4: _index+6], 16)}
  167. # )
  168. step["power{}".format(_index/6 + 1)] = int(data[_index: _index+4], 16)
  169. step["discount{}".format(_index/6 + 1)] = int(data[_index+4: _index+6], 16)
  170. return step
  171. @stepPower.setter
  172. def stepPower(self, value):
  173. content = ""
  174. for _item in value:
  175. content += "{:04X}{:02X}".format(int(_item["power"]), int(_item["discount"]))
  176. self._send_data("01F1", content)
  177. @property
  178. def timeRule(self):
  179. result = self._send_data("01B8", "01")
  180. mobilePrice = int(result["data"][12: 16], 16)
  181. mobileTime = int(result["data"][16: 20], 16)
  182. mobileOnsale = int(result["data"][20: 22], 16)
  183. icPrice = int(result["data"][22: 26], 16)
  184. icTime = int(result["data"][26: 30], 16)
  185. coinPrice = int(result["data"][30: 34], 16)
  186. coinTime = int(result["data"][34: 38], 16)
  187. return {
  188. "timePrice": mobilePrice,
  189. "timeNum": mobileTime,
  190. "timeOnsale": mobileOnsale,
  191. "mobilePrice": mobilePrice,
  192. "mobileTime": mobileTime,
  193. "mobileOnsale": mobileOnsale,
  194. "icPrice": icPrice,
  195. "icTime": icTime,
  196. "coinPrice": coinPrice,
  197. "coinTime": coinTime
  198. }
  199. @timeRule.setter
  200. def timeRule(self, value):
  201. mobilePrice = value["mobilePrice"]
  202. mobileTime = value["mobileTime"]
  203. mobileOnsale = value["mobileOnsale"]
  204. icPrice = value["icPrice"]
  205. icTime = value["icTime"]
  206. coinPrice = value['coinPrice']
  207. coinTime = value['coinTime']
  208. self._send_data(
  209. "01B7",
  210. "{:04X}{:04X}{:02X}{:04X}{:04X}{:04X}{:04X}".format(int(mobilePrice), int(mobileTime), int(mobileOnsale), int(icPrice), int(icTime), int(coinPrice), int(coinTime))
  211. )
  212. @property
  213. def elecRule(self):
  214. result = self._send_data("01F7", "01")
  215. elecPrice = int(result['data'][12:16], 16)
  216. elecNum = int(result['data'][16:20], 16) / 100.0
  217. elecOnsale = int(result['data'][20:22], 16)
  218. return {"elecPrice": elecPrice, "elecNum": elecNum, "elecOnsale": elecOnsale}
  219. @elecRule.setter
  220. def elecRule(self, value):
  221. """设置电量 前台过来单位为度 发送主板需要修改为0.1度"""
  222. elecPrice = value["elecPrice"]
  223. elecNum = value["elecNum"]
  224. elecOnsale = value["elecOnsale"]
  225. self._send_data(
  226. "01F8",
  227. "{:04X}{:04X}{:02X}".format(int(elecPrice), int(elecNum)*100, int(elecOnsale))
  228. )
  229. def _get_all_status(self):
  230. result = self._send_data("01ED", "0100")
  231. portCount = int(result["data"][10: 12], 16)
  232. portData = result["data"][12: 12+portCount*4]
  233. portDict = dict()
  234. for _i in range(portCount):
  235. _port = str(int(portData[_i*4: _i*4+2], 16))
  236. _status = portData[_i*4+2: _i*4+4]
  237. if _status == "01":
  238. _tStatus = Const.DEV_WORK_STATUS_IDLE
  239. elif _status == "02":
  240. _tStatus = Const.DEV_WORK_STATUS_WORKING
  241. elif _status == "03":
  242. _tStatus = Const.DEV_WORK_STATUS_FORBIDDEN
  243. elif _status == "04":
  244. _tStatus = Const.DEV_WORK_STATUS_FAULT
  245. else:
  246. _tStatus = Const.DEV_WORK_STATUS_FAULT
  247. portDict[_port] = {"status": _tStatus}
  248. return portDict
  249. def _get_port_info(self, port):
  250. # TODO 电流单位未知
  251. result = self._send_data("{:02X}EF".format(int(port)), "00")
  252. _status = result["data"][12: 14]
  253. if _status == "01":
  254. status = Const.DEV_WORK_STATUS_IDLE
  255. elif _status == "02":
  256. status = Const.DEV_WORK_STATUS_WORKING
  257. elif _status == "03":
  258. status = Const.DEV_WORK_STATUS_FORBIDDEN
  259. elif _status == "04":
  260. status = Const.DEV_WORK_STATUS_FAULT
  261. else:
  262. status = Const.DEV_WORK_STATUS_FAULT
  263. left = int(result["data"][14: 18], 16)
  264. power = int(result["data"][18: 22], 16) / 10.0
  265. otherConf = self.device.get("otherConf", dict())
  266. chargeMode = otherConf.get("chargeType", self.DEFAULT_CHARGE_TYPE)
  267. if chargeMode == "elec":
  268. left /= 100.0
  269. return {
  270. "status": status,
  271. "power": power,
  272. "left{}".format(chargeMode.capitalize()): left
  273. }
  274. def _get_port_elec(self):
  275. """获取端口实时用电量"""
  276. result = self._send_data("01E9", "01")
  277. data = result['data'][12: -2]
  278. for _index in range(0, len(data), 4):
  279. tUsedElec = int(data[_index: _index+4], 16)
  280. Device.update_dev_control_cache(self.device.devNo, {str(_index/4+1): {"usedElec": tUsedElec}})
  281. @staticmethod
  282. def _parse_event_C9(data):
  283. """
  284. :param data:
  285. :return:
  286. """
  287. # TODO zjl 这个订单序号有什么用
  288. portStr = str(int(data[2: 4], 16))
  289. orderNo = str(int(data[10:26], 16))
  290. serialNo = str(int(data[26:30], 16))
  291. usedCoins = str(int(data[30:36], 16) / 100.0)
  292. usedTime = str(int(data[36: 40], 16))
  293. leftTime = str(int(data[40:48], 16))
  294. return {
  295. 'portStr': portStr,
  296. 'orderNo': orderNo,
  297. 'serialNo': serialNo,
  298. 'usedCoins': usedCoins,
  299. 'usedTime': usedTime,
  300. 'leftTime': leftTime
  301. }
  302. @staticmethod
  303. def _parse_event_C8(data):
  304. # TODO zjl 目前没有刷卡消费的订单 事分缓急 先不做
  305. return {}
  306. @staticmethod
  307. def _parse_event_C4(data):
  308. # TODO 故障码 55-255
  309. portStr = str(int(data[2: 4], 16))
  310. status = int(data[10:12], 16)
  311. return {
  312. "status": status,
  313. "portStr": portStr
  314. }
  315. @staticmethod
  316. def _parse_event_B5(data):
  317. # TODO 测试 感觉单位像是分钟而不是秒
  318. port = int(data[2:4], 16)
  319. serialNo = int(data[10:14], 16)
  320. usedCoins = str(int(data[14:22], 16) / 100.0)
  321. usedTime = str(int(data[22:30], 16))
  322. finishedStamp = str(int(data[30:38], 16))
  323. return {
  324. 'portStr': port,
  325. 'serialNo': serialNo,
  326. 'usedCoins': usedCoins,
  327. 'usedTime': usedTime,
  328. 'finishedStamp': finishedStamp
  329. }
  330. @staticmethod
  331. def _parse_event_B6(data):
  332. port = int(data[2:4], 16)
  333. serialNo = int(data[10:14], 16)
  334. cardNo = data[14:24]
  335. usedCoins = str(int(data[24:32], 16) / 100.0)
  336. balance = str(int(data[32:40], 16) / 100.0)
  337. usedTime = str(int(data[40:48], 16))
  338. finishedStamp = str(int(data[48:56], 16))
  339. return {
  340. 'portStr': port,
  341. 'serialNo': serialNo,
  342. 'cardNo': cardNo,
  343. 'usedCoins': usedCoins,
  344. 'balance': balance,
  345. 'usedTime': usedTime,
  346. 'finishedStamp': finishedStamp
  347. }
  348. @staticmethod
  349. def _parse_event_EA(data):
  350. portStr = str(int(data[2: 4], 16))
  351. reasonCode = int(data[10:12], 16)
  352. leftElec = int(data[12:16], 16) / 100.0
  353. return {
  354. "reasonCode": reasonCode,
  355. "leftElec": leftElec,
  356. "portStr": portStr
  357. }
  358. @staticmethod
  359. def _parse_event_F0(data):
  360. totalElec = int(data[10:14], 16) / 1000.0
  361. return {"totalElec": totalElec}
  362. @staticmethod
  363. def _parse_event_F9(data):
  364. port = int(data[2:4], 16)
  365. cardNo = int(data[10:18], 16)
  366. consumeMoney = round(int(data[19:22], 16) * 0.01, 2)
  367. return {"port": port, "cardNo": cardNo, "consumeMoney": consumeMoney}
  368. @staticmethod
  369. def _parse_event_FA(data):
  370. port = int(data[2:4], 16)
  371. cardNo = int(data[10:18], 16)
  372. refundMoney = round(int(data[19:22], 16) * 0.01, 2)
  373. return {"port": port, "cardNo": cardNo, "refundMoney": refundMoney}
  374. def test(self, coins):
  375. orderNo = random.randint(10000, 99999)
  376. return self._start_device("1", orderNo, coins, coins)
  377. def get_device_function_by_key(self, keyName):
  378. if "poweroffTime" in keyName:
  379. return {"poweroffTime": self.poweroffTime}
  380. if "curElec" in keyName:
  381. return {"curElec": self.curElec}
  382. if "totalCoinConsume" in keyName:
  383. return {"totalCoinConsume": self.totalCoinConsume}
  384. if "totalCardConsume" in keyName:
  385. return {"totalCardConsume": self.totalCardConsume}
  386. if "emptyTime" in keyName:
  387. return {"emptyTime": self.emptyTime}
  388. if "emptyPower" in keyName:
  389. return {"emptyPower": self.emptyPower}
  390. if "consumeMode" in keyName:
  391. return {"consumeMode": self.chargeType}
  392. if "mobilePrice" in keyName:
  393. return self.timeRule
  394. if "elecPrice" in keyName:
  395. return self.elecRule
  396. if "power1" in keyName:
  397. return self.stepPower
  398. if "standElec" in keyName:
  399. return self.standElec
  400. return {}
  401. def set_device_function(self, request, lastSetConf):
  402. if "recover" in request.POST:
  403. self._set_recover()
  404. if "clearLineTime" in request.POST:
  405. self._set_clear_line_time()
  406. if "reboot" in request.POST:
  407. self._set_reboot()
  408. def set_device_function_param(self, request, lastSetConf):
  409. if "consumeMode" in request.POST:
  410. self.chargeType = request.POST.get("consumeMode")
  411. if "mobilePrice" in request.POST:
  412. mobilePrice = request.POST.get("mobilePrice")
  413. mobileTime = request.POST.get("mobileTime")
  414. mobileOnsale = request.POST.get("mobileOnsale")
  415. icPrice = request.POST.get("icPrice")
  416. icTime = request.POST.get("icTime")
  417. coinPrice = request.POST.get("coinPrice")
  418. coinTime = request.POST.get("coinTime")
  419. self.timeRule = {"mobilePrice": mobilePrice, "mobileTime": mobileTime, "mobileOnsale": mobileOnsale, "icPrice": icPrice, "icTime": icTime, "coinPrice": coinPrice, "coinTime": coinTime}
  420. if "elecPrice" in request.POST:
  421. elecPrice = request.POST.get("elecPrice")
  422. elecNum = request.POST.get("elecNum")
  423. elecOnsale = request.POST.get("elecOnsale")
  424. self.elecRule = {"elecPrice": elecPrice, "elecNum": elecNum, "elecOnsale": elecOnsale}
  425. if "power1" in request.POST:
  426. step = list()
  427. for _index in range(1, 5):
  428. step.append({"power": request.POST['power{}'.format(_index)], "discount": request.POST["discount{}".format(_index)]})
  429. self.stepPower = step
  430. if "standElec" in request.POST or "maxElec" in request.POST:
  431. standElec = request.POST.get("standElec")
  432. maxElec = request.POST.get("maxElec")
  433. self.standElec = {"standElec": standElec, "maxElec": maxElec}
  434. if "poweroffTime" in request.POST:
  435. poweroffTime = request.POST.get("poweroffTime")
  436. self.poweroffTime = poweroffTime
  437. if "emptyTime" in request.POST:
  438. emptyTime = request.POST.get("emptyTime")
  439. self.emptyTime = emptyTime
  440. if "emptyPower" in request.POST:
  441. emptyPower = request.POST.get("emptyPower")
  442. self.emptyPower = emptyPower
  443. def get_port_status_from_dev(self):
  444. result = self._get_all_status()
  445. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  446. Device.update_dev_control_cache(
  447. self._device['devNo'],
  448. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts}
  449. )
  450. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  451. for strPort, info in result.items():
  452. if strPort in ctrInfo:
  453. ctrInfo[strPort].update({'status': info['status']})
  454. else:
  455. ctrInfo[strPort] = info
  456. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  457. return result
  458. def get_port_status(self, force=False):
  459. """强制改变状态 这个板子的路数总是改变 每次都直接重新获取吧"""
  460. self.get_port_status_from_dev()
  461. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  462. if 'allPorts' not in ctrInfo:
  463. self.get_port_status_from_dev()
  464. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  465. allPorts = ctrInfo.get("allPorts", 10)
  466. statusDict = {}
  467. for ii in range(allPorts):
  468. tempDict = ctrInfo.get(str(ii + 1), {})
  469. if tempDict.has_key('status'):
  470. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  471. elif tempDict.has_key('isStart'):
  472. if tempDict['isStart']:
  473. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  474. else:
  475. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  476. else:
  477. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  478. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  479. Device.update_dev_control_cache(self._device['devNo'],
  480. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  481. return statusDict
  482. def get_port_info(self, line):
  483. result = self._get_port_info(line)
  484. result.update({"port": line})
  485. return result
  486. def start_device(self, package, openId, attachParas):
  487. chargeIndex = attachParas.get("chargeIndex")
  488. if not chargeIndex:
  489. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  490. orderNo = attachParas.get("orderNo") or ConsumeRecord.make_no(self.device.logicalCode, UserConsumeSubType.NETPAY)
  491. coins = package.get("coins")
  492. balance = None
  493. if openId:
  494. user = MyUser.objects.get(groupId=self._device['groupId'], openId=openId)
  495. balance = user.balance
  496. start_timestamp = int(time.time())
  497. otherConf = self.device.get("otherConf", dict())
  498. chargeMode = otherConf.get("chargeType", self.DEFAULT_CHARGE_TYPE)
  499. portCache = {
  500. 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'),
  501. 'status': Const.DEV_WORK_STATUS_WORKING,
  502. 'coins': coins,
  503. 'isStart': True,
  504. 'openId': openId,
  505. 'refunded': False,
  506. 'vCardId': self._vcard_id,
  507. "chargeType": chargeMode,
  508. }
  509. if chargeMode == self.DEFAULT_CHARGE_TYPE:
  510. rule = self.timeRule
  511. price = rule["timePrice"]
  512. needTime = float(coins) / float(price / 100.0) * rule["timeNum"]
  513. portCache.update({"needTime": needTime})
  514. else:
  515. rule = self.elecRule
  516. price = rule["elecPrice"]
  517. needElec = float(coins) / float(price / 100.0) * rule["elecNum"] / 10.0
  518. portCache.update({"needElec": needElec})
  519. result = self._start_device(portStr=chargeIndex, orderNo=orderNo, money=coins, leftMoney=balance)
  520. Device.update_dev_control_cache(self.device.devNo, {chargeIndex: portCache})
  521. result['consumeOrderNo'] = orderNo
  522. result["finishedTime"] = start_timestamp + 24 * 60 * 60
  523. return result
  524. def stop(self, port=None):
  525. if not port:
  526. return
  527. self._stop(str(port))
  528. @property
  529. def isHaveStopEvent(self):
  530. return True
  531. def active_deactive_port(self, port, active):
  532. if not active:
  533. return self._stop(str(port))
  534. def analyze_event_data(self, data):
  535. cmdCode = data[6:8]
  536. func = getattr(self, "_parse_event_{}".format(cmdCode.upper()), None)
  537. if func:
  538. result = func(data)
  539. result["cmdCode"] = cmdCode
  540. return result
  541. else:
  542. logger.info("no <{}> parser".format(cmdCode))
  543. def dealer_get_port_status(self):
  544. self._get_port_elec()
  545. data = self.get_port_status()
  546. return data