suzhoubeisiyun.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import random
  5. import logging
  6. import binascii
  7. import time
  8. from typing import TYPE_CHECKING
  9. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, reverse_hex
  10. from apps.web.core.networking import MessageSender
  11. from apps.web.core.exceptions import ServiceException
  12. from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT
  13. from apps.web.device.models import Device
  14. from apps.web.user.models import ConsumeRecord
  15. from apilib.monetary import VirtualCoin
  16. logger = logging.getLogger(__name__)
  17. if TYPE_CHECKING:
  18. pass
  19. class ChargeModeMap(object):
  20. TIME_QUOTA = 1
  21. POWER_QUOTA = 2
  22. ELEC_QUOTA = 3
  23. FREE_QUOTA = 4
  24. INTERVAL_QUOTA = 5
  25. class PortStatusCode(object):
  26. DEV_WORK_STATUS_IDLE = 0
  27. DEV_WORK_STATUS_IDLE_POWER_NORMAL_FAULT_RELAY_CONNECT = 1
  28. DEV_WORK_STATUS_IDLE_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL = 2
  29. DEV_WORK_STATUS_IDLE_FAULT_OVERLOAD_FAULT_RELAY_CONNECT = 3
  30. DEV_WORK_STATUS_WORKING = 4
  31. DEV_WORK_STATUS_WORKING_POWER_NORMAL_FAULT_RELAY_CONNECT = 5
  32. DEV_WORK_STATUS_WORKING_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL = 6
  33. DEV_WORK_STATUS_WORKING_FAULT_OVERLOAD_FAULT_RELAY_CONNECT = 7
  34. DEV_WORK_STATUS_WORKING_COIN = 8
  35. DEV_WORK_STATUS_WORKING_COIN_POWER_NORMAL_FAULT_RELAY_CONNECT = 9
  36. DEV_WORK_STATUS_WORKING_COIN_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL = 10
  37. DEV_WORK_STATUS_WORKING_COIN_FAULT_OVERLOAD_FAULT_RELAY_CONNECT = 11
  38. class BILLING_TYPE(object):
  39. """
  40. 充电方式
  41. """
  42. TIME = "time"
  43. ELEC = "elec"
  44. POWER = "power"
  45. FREE = "free"
  46. INTERVAL_QUOTA = "interval_quota"
  47. class ChargingBeiSiYunBox(SmartBox):
  48. def _encrypt_func(self, bArray, kArray, r, en=True):
  49. """
  50. :param bArray: 加密的字节数组
  51. :param kArray: 加密的字节数组 参与加密
  52. :param r: 加密的随机字符 0-255 单字节
  53. :param en: 是否为加密 True = 加密 False = 解密
  54. """
  55. kenLen = 10
  56. result = bytearray()
  57. for i in range(len(bArray)):
  58. temp_char = bArray[i]
  59. s = i % kenLen + 1
  60. if s == kenLen:
  61. s = 0
  62. else:
  63. s = s
  64. k = kArray[s]
  65. if en:
  66. rc = (temp_char + k + r) % 256
  67. else:
  68. rc = (temp_char - k - r) % 256
  69. result.insert(i, rc)
  70. # print("[encrypt_func] result = {}, hex result = {}".format(result, binascii.hexlify(result)))
  71. return result
  72. def _send_mqtt(self, funCode, data=None, cmd=None, timeout=MQTT_TIMEOUT.NORMAL):
  73. """
  74. 发送数据到mqtt服务器
  75. :param funCode:
  76. :param data:
  77. :param cmd:
  78. :param timeout:
  79. :return:
  80. """
  81. if cmd is None:
  82. cmd = DeviceCmdCode.OPERATE_DEV_SYNC
  83. if data is None:
  84. data = "00"
  85. result = MessageSender.send(device=self.device, cmd=cmd, payload={
  86. "IMEI": self.device.devNo,
  87. "funCode": funCode,
  88. "data": data
  89. }, timeout=timeout)
  90. if "rst" in result and result.get("rst") != 0:
  91. if result.get("rst") == -1:
  92. raise ServiceException({"result": 2, "description": u"网络故障,请重新试试"})
  93. if result.get("rst") == 1:
  94. raise ServiceException({"result": 2, "description": u"充电桩无响应,请稍后再试试"})
  95. return result
  96. def _start_remote(self, port, method, orderType, balance, orderNo, maxTime=0, spendMoney=0, other=0):
  97. portHex = fill_2_hexByte(hex(int(port)), 2)
  98. methodHex = fill_2_hexByte(hex(int(method)), 2)
  99. orderTypeHex = fill_2_hexByte(hex(int(orderType)), 2)
  100. balanceHex = fill_2_hexByte(hex(int(balance)), 4)
  101. orderNoHex = fill_2_hexByte(hex(int(orderNo)), 10)
  102. maxTimeHex = fill_2_hexByte(hex(int(maxTime)), 2)
  103. spendMoneyHex = fill_2_hexByte(hex(int(spendMoney)), 4)
  104. otherHex = fill_2_hexByte(hex(int(other)), 4)
  105. data = portHex + methodHex + orderTypeHex + balanceHex + orderNoHex + maxTimeHex + spendMoneyHex + otherHex
  106. result = self._send_mqtt("A2", data=data)
  107. # deviceVersion = int(result["data"][2:8], 16)
  108. # port = int(result["data"][8:10], 16)
  109. # orderNo = int(result["data"][10:20], 16)
  110. # infoDict = {
  111. # "deviceVersion": deviceVersion,
  112. # "port": port,
  113. # "orderNo": orderNo
  114. # }
  115. return result
  116. def _update_charge_balance(self, port, balance, other=0):
  117. portHex = fill_2_hexByte(hex(int(port)), 2)
  118. balanceHex = fill_2_hexByte(hex(int(balance)), 4)
  119. otherHex = fill_2_hexByte(hex(int(other), 4))
  120. data = portHex + balanceHex + otherHex
  121. result = self._send_mqtt("A3", data=data)
  122. deviceVersion = int(result["data"][2:8], 16)
  123. port = int(result["data"][8:10], 16)
  124. orderNo = int(result["data"][10:20], 16)
  125. newBalance = int(result["data"][20:24], 16) / 100
  126. infoDict = {
  127. "deviceVersion": deviceVersion,
  128. "port": port,
  129. "orderNo": orderNo,
  130. "newBalance": newBalance,
  131. }
  132. return infoDict
  133. def _stop_remote(self, port, other=0):
  134. portHex = fill_2_hexByte(hex(int(port)), 2)
  135. otherHex = fill_2_hexByte(hex(int(other)), 4)
  136. data = portHex + otherHex
  137. result = self._send_mqtt("A4", data=data)
  138. deviceVersion = int(result["data"][2:8], 16)
  139. port = int(result["data"][8:10], 16)
  140. orderNo = int(result["data"][10:20], 16)
  141. chargeStatus = int(result["data"][20:22], 16)
  142. usedElec = int(result["data"][22:28], 16) / 1000
  143. usedMoney = int(result["data"][28:32], 16) / 100
  144. self._ack(port)
  145. infoDict = {
  146. "deviceVersion": deviceVersion,
  147. "port": port,
  148. "orderNo": orderNo,
  149. "chargeStatus": chargeStatus,
  150. "usedElec": usedElec,
  151. "usedMoney": usedMoney,
  152. }
  153. return infoDict
  154. def _ack(self, port):
  155. portHex = fill_2_hexByte(hex(int(port)), 2)
  156. data = portHex + "01"
  157. self._send_mqtt("AA", data=data, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  158. def _check_MCU_code(self):
  159. result = self._send_mqtt("B0", data="00")
  160. deviceVersion = int(result["data"][2:8], 16)
  161. deviceCode = int(result["data"][8:], 16)
  162. infoDict = {
  163. "deviceVersion": deviceVersion,
  164. "deviceCode": deviceCode
  165. }
  166. return infoDict
  167. def _check_MCU_temperature(self):
  168. result = self._send_mqtt("B1", data="00")
  169. deviceVersion = int(result["data"][2:8], 16)
  170. temperature = int(result["data"][8:], 16)
  171. infoDict = {
  172. "deviceVersion": deviceVersion,
  173. "temperature": temperature
  174. }
  175. return infoDict
  176. def _relay_control(self, relay, control):
  177. relayHex = fill_2_hexByte(hex(int(relay)), 2)
  178. controlHex = fill_2_hexByte(hex(int(control)), 2)
  179. data = relayHex + controlHex
  180. self._send_mqtt("B2", data=data, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  181. def _update_device(self, typeCode, code):
  182. typeCodeHex = fill_2_hexByte(hex(int(typeCode)), 2)
  183. codeHex = fill_2_hexByte(hex(int(code)), 6)
  184. data = typeCodeHex + codeHex
  185. self._send_mqtt("B3", data=data, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  186. def _restart_device(self):
  187. self._send_mqtt("B4", data="00", cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  188. def _set_sound(self, sound):
  189. self._send_mqtt("B5", data=sound, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  190. def _remote_set_device_function_parameter(self, infoDic):
  191. minPowerHex = fill_2_hexByte(hex(int(float(infoDic.get("minPower")) / 0.2)), 2)
  192. checkTimeHex = fill_2_hexByte(hex(int(infoDic.get("checkTime"))), 2)
  193. powerFailureTimeHex = fill_2_hexByte(hex(int(infoDic.get("powerFailureTime")) / 5), 2)
  194. checkAutoStopHex = fill_2_hexByte(hex(int(infoDic.get("checkAutoStop"))), 2)
  195. floatTimeHex = fill_2_hexByte(hex(int(infoDic.get("floatTime"))), 2)
  196. price = fill_2_hexByte(hex(int(float(infoDic.get("price")) * 100)), 4)
  197. overloadPowerHex = fill_2_hexByte(hex(int(infoDic.get("overloadPower"))), 4)
  198. onceChargeTimeHex = fill_2_hexByte(hex(int(float(infoDic.get("onceChargeTime")) / 5)), 2)
  199. temperatureTresholdHex = fill_2_hexByte(hex(int(infoDic.get("checkTime"))), 2)
  200. powerPrice = infoDic.get("powerPrice")
  201. if len(powerPrice) < 10:
  202. i = len(powerPrice)
  203. while i < 10:
  204. powerPrice.update({str(i): {u'max': 0xffff, u'price': 655.35}})
  205. i += 1
  206. powerPriceHex = ""
  207. for i in range(10):
  208. max = powerPrice[str(i)]["max"]
  209. sectionPrice = int(powerPrice[str(i)]["price"] * 100)
  210. powerPriceHex = powerPriceHex + fill_2_hexByte(hex(int(max))) + fill_2_hexByte(hex(sectionPrice))
  211. data = minPowerHex + checkTimeHex + powerFailureTimeHex + checkAutoStopHex + floatTimeHex + \
  212. price + overloadPowerHex + onceChargeTimeHex + temperatureTresholdHex + powerPriceHex
  213. self._send_mqtt("B6", data=data, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  214. def _remote_get_dev_setting(self):
  215. result = self._send_mqtt("B7", data="00")
  216. data = result.get("data")[10:]
  217. minPower = int(data[0:2], 16) * 0.2
  218. checkTime = int(data[2:4], 16)
  219. powerFailureTime = int(data[4:6], 16) * 5
  220. checkAutoStop = int(data[6:8], 16)
  221. floatTime = int(data[8:10], 16)
  222. price = float(int(data[10:14], 16)) / 100
  223. overloadPower = int(data[14:18], 16)
  224. onceChargeTime = int(data[18:20], 16) * 5
  225. temperatureTreshold = int(data[20:22], 16)
  226. powerPriceHex = data[22:]
  227. packages = []
  228. for i in range(10):
  229. max = int(powerPriceHex[i * 8:i * 8 + 8][:4], 16)
  230. sectionPrice = float(int(powerPriceHex[i * 8:i * 8 + 8][4:], 16)) / 100
  231. if max != 65535 and sectionPrice != 6553.55:
  232. packages.append({"max": max, "price": sectionPrice})
  233. sound = self.device.otherConf.get('sound')
  234. billingType = self.device.otherConf.get('billingType')
  235. infoDict = {
  236. "minPower": minPower,
  237. "checkTime": checkTime,
  238. "powerFailureTime": powerFailureTime,
  239. "checkAutoStop": checkAutoStop,
  240. "floatTime": floatTime,
  241. "price": price,
  242. "overloadPower": overloadPower,
  243. "onceChargeTime": onceChargeTime,
  244. "temperatureTreshold": temperatureTreshold,
  245. "packages": packages,
  246. "sound": sound,
  247. "billingType": billingType
  248. }
  249. return infoDict
  250. def _get_device_status_info(self):
  251. result = self._send_mqtt("A6", "00")
  252. deviceVersion = int(result["data"][2:8], 16)
  253. typeOfDevice = int(result["data"][8:10], 16)
  254. other = int(result["data"][10:12], 16)
  255. portStatus = result["data"][12:]
  256. if typeOfDevice == 1:
  257. portNum = 2
  258. elif typeOfDevice == 2:
  259. portNum = 10
  260. elif typeOfDevice == 3:
  261. portNum = 16
  262. ii = 0
  263. portNo = 0
  264. portStatusDict = {}
  265. while ii < portNum:
  266. statusTemp = portStatus[ii * 2:ii * 2 + 2]
  267. if statusTemp == "00":
  268. status = {'status': Const.DEV_WORK_STATUS_IDLE,
  269. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE}
  270. elif statusTemp == "01":
  271. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT,
  272. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE_POWER_NORMAL_FAULT_RELAY_CONNECT}
  273. elif statusTemp == "02":
  274. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  275. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL}
  276. elif statusTemp == "03":
  277. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  278. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE_FAULT_OVERLOAD_FAULT_RELAY_CONNECT}
  279. elif statusTemp == "04":
  280. status = {'status': Const.DEV_WORK_STATUS_WORKING,
  281. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING}
  282. elif statusTemp == "05":
  283. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT,
  284. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_POWER_NORMAL_FAULT_RELAY_CONNECT}
  285. elif statusTemp == "06":
  286. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  287. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL}
  288. elif statusTemp == "07":
  289. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  290. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_FAULT_OVERLOAD_FAULT_RELAY_CONNECT}
  291. elif statusTemp == "08":
  292. status = {'status': Const.DEV_WORK_STATUS_APPOINTMENT,
  293. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN}
  294. elif statusTemp == "09":
  295. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT,
  296. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN_POWER_NORMAL_FAULT_RELAY_CONNECT}
  297. elif statusTemp == "10":
  298. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  299. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL}
  300. elif statusTemp == "11":
  301. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  302. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN_FAULT_OVERLOAD_FAULT_RELAY_CONNECT}
  303. else:
  304. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  305. ii += 1
  306. portNo += 1
  307. portStatusDict[str(portNo)] = status
  308. infoDict = {
  309. "deviceVersion": deviceVersion,
  310. "typeOfDevice": typeOfDevice,
  311. "other": other,
  312. "portStatusDict": portStatusDict
  313. }
  314. return infoDict
  315. def analyze_event_data(self, data):
  316. cmdCode = data[0:2]
  317. if cmdCode == "A4":
  318. deviceVersion = int(reverse_hex(data[2:8]), 16)
  319. port = int(data[8:10], 16)
  320. orderNo = data[10:20],
  321. reasonCode = int(data[20:22], 16)
  322. usedElec = int(reverse_hex(data[22:28]), 16) / 1000
  323. usedMoney = int(reverse_hex(data[28:32]), 16) / 100
  324. if reasonCode == 1:
  325. reason = u"浮充开始"
  326. elif reasonCode == 2:
  327. reason = u"主动关闭"
  328. elif reasonCode == 3:
  329. reason = u"插头拔出"
  330. elif reasonCode == 4:
  331. reason = u"充电完成"
  332. elif reasonCode == 5:
  333. reason = u"充满自停"
  334. elif reasonCode == 6:
  335. reason = u"功率过载"
  336. elif reasonCode == 7:
  337. reason = u"电流过载"
  338. elif reasonCode == 8:
  339. reason = u"充电失败,检测功率过低"
  340. elif reasonCode == 9:
  341. reason = u"温度异常"
  342. elif reasonCode == 10:
  343. reason = u"消费用完"
  344. return {
  345. "cmdCode": cmdCode,
  346. "deviceVersion": deviceVersion,
  347. "port": port,
  348. "orderNo": orderNo,
  349. "reasonCode": reasonCode,
  350. "reason": reason,
  351. "usedElec": usedElec,
  352. "usedMoney": usedMoney
  353. }
  354. elif cmdCode == "A5":
  355. deviceCode = int(data[2:8], 16)
  356. port = int(data[8:10], 16)
  357. orderNo = int(data[10:20], 16)
  358. outputVoltage = int(reverse_hex(data[20:24]), 16) / 100
  359. outputElec = int(reverse_hex(data[24:28]), 16) / 1000
  360. power = int(reverse_hex(data[28:34]), 16) / 1000
  361. usedElec = int(reverse_hex(data[34:40]), 16) / 1000
  362. usedMoney = int(reverse_hex(data[40:44])), 16 / 100
  363. return {
  364. "cmdCode": cmdCode,
  365. "deviceCode": deviceCode,
  366. "port": port,
  367. "orderNo": orderNo,
  368. "outputVoltage": outputVoltage,
  369. "outputElec": outputElec,
  370. "power": power,
  371. "usedElec": usedElec,
  372. "usedMoney": usedMoney
  373. }
  374. elif cmdCode == "A6":
  375. deviceVersion = int(data[2:8], 16)
  376. typeOfDevice = int(data[8:10], 16)
  377. other = int(data[10:12], 16)
  378. portStatus = data[12:]
  379. if typeOfDevice == 1:
  380. portNum = 2
  381. elif typeOfDevice == 2:
  382. portNum = 10
  383. elif typeOfDevice == 3:
  384. portNum = 16
  385. ii = 0
  386. portNo = 1
  387. portStatusDict = {}
  388. while ii < portNum:
  389. statusTemp = portStatus[ii * 2:ii * 2 + 2]
  390. if statusTemp == "00":
  391. status = {'status': Const.DEV_WORK_STATUS_IDLE,
  392. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE}
  393. elif statusTemp == "01":
  394. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT,
  395. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE_POWER_NORMAL_FAULT_RELAY_CONNECT}
  396. elif statusTemp == "02":
  397. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  398. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL}
  399. elif statusTemp == "03":
  400. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  401. "statusCode": PortStatusCode.DEV_WORK_STATUS_IDLE_FAULT_OVERLOAD_FAULT_RELAY_CONNECT}
  402. elif statusTemp == "04":
  403. status = {'status': Const.DEV_WORK_STATUS_WORKING,
  404. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING}
  405. elif statusTemp == "05":
  406. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT,
  407. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_POWER_NORMAL_FAULT_RELAY_CONNECT}
  408. elif statusTemp == "06":
  409. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  410. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL}
  411. elif statusTemp == "07":
  412. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  413. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_FAULT_OVERLOAD_FAULT_RELAY_CONNECT}
  414. elif statusTemp == "08":
  415. status = {'status': Const.DEV_WORK_STATUS_WORKING,
  416. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN}
  417. elif statusTemp == "09":
  418. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT,
  419. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN_POWER_NORMAL_FAULT_RELAY_CONNECT}
  420. elif statusTemp == "10":
  421. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  422. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN_FAULT_OVERLOAD_RELAY_CONNECT_NORMAL}
  423. elif statusTemp == "11":
  424. status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD,
  425. "statusCode": PortStatusCode.DEV_WORK_STATUS_WORKING_COIN_FAULT_OVERLOAD_FAULT_RELAY_CONNECT}
  426. else:
  427. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  428. ii += 1
  429. portNo += 1
  430. portStatusDict[str(portNo)] = status
  431. return {
  432. "deviceVersion": deviceVersion,
  433. "typeOfDevice": typeOfDevice,
  434. "other": other,
  435. "portStatusDict": portStatusDict
  436. }
  437. elif cmdCode == "A7":
  438. deviceCode = int(data[2:8], 16)
  439. cardNo = int(data[8:16], 16)
  440. mode = int(data[16:18], 16)
  441. port = int(data[18:20], 16)
  442. return {
  443. "deviceCode": deviceCode,
  444. "cardNo": cardNo,
  445. "mode": mode,
  446. "port": port
  447. }
  448. elif cmdCode == "A8":
  449. deviceCode = int(data[2:8], 16)
  450. cardNo = int(data[8:16], 16)
  451. return {
  452. "deviceCode": deviceCode,
  453. "cardNo": cardNo
  454. }
  455. elif cmdCode == "AB":
  456. deviceCode = int(data[2:8], 16)
  457. port = int(data[8:10], 16)
  458. coins = int(data[10:14], 16)
  459. return {
  460. "deviceCode": deviceCode,
  461. "port": port,
  462. "coins": coins
  463. }
  464. elif cmdCode == "B8":
  465. deviceCode = int(data[2:8], 16)
  466. return {
  467. "deviceCode": deviceCode
  468. }
  469. def _check_package(self, package):
  470. billingType = self.device.otherConf.get('billingType','time')
  471. nowTime = int(time.time())
  472. unit = self.device.otherConf.get('price')
  473. onceChargeTime = self.device.otherConf.get('onceChargeTime') or self._remote_get_dev_setting()['onceChargeTime']
  474. onceChargeTime = int(onceChargeTime)
  475. if unit != 0:
  476. if billingType == BILLING_TYPE.TIME:
  477. method = '01'
  478. needTime = float(package['price']) / float(unit) * 60
  479. elif billingType == BILLING_TYPE.POWER:
  480. method = '02'
  481. needTime = 0
  482. elif billingType == BILLING_TYPE.ELEC:
  483. method = '03'
  484. needTime = package['price'] / float(unit)
  485. elif billingType == BILLING_TYPE.FREE:
  486. method = '04'
  487. needTime = 0
  488. elif billingType == BILLING_TYPE.INTERVAL_QUOTA:
  489. method = '05'
  490. needTime = 0
  491. else:
  492. method = '04'
  493. needTime = 0
  494. if needTime > onceChargeTime:
  495. needTime = onceChargeTime
  496. finishedTime = nowTime + needTime * 60 * 60
  497. return method, billingType, needTime, finishedTime
  498. def start_device(self, package, openId, attachParas):
  499. chargeIndex = attachParas.get("chargeIndex")
  500. port = int(chargeIndex) - 1
  501. coins = float(package['price'])
  502. balance = int(coins * 100)
  503. if not chargeIndex:
  504. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  505. if not openId:
  506. raise ServiceException({"result": 2, "description": u"本设备暂不支持上分"})
  507. devStatus = self._get_device_status_info()
  508. if devStatus["portStatusDict"][chargeIndex]['status'] == Const.DEV_WORK_STATUS_IDLE:
  509. method, billingType, needTime, finishedTime = self._check_package(package)
  510. orderType = '01'
  511. orderNo = attachParas['orderNo'][-10:]
  512. result = self._start_remote(port, method, orderType, balance, orderNo)
  513. portDict = {
  514. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  515. 'status': Const.DEV_WORK_STATUS_WORKING,
  516. 'finishedTime': finishedTime,
  517. 'coins': coins,
  518. 'isStart': True,
  519. 'orderNo': attachParas['orderNo'],
  520. 'useType': 'mobile',
  521. 'orderType': orderType,
  522. 'openId': openId,
  523. 'refunded': False,
  524. 'billingType': billingType,
  525. }
  526. if billingType == 'time':
  527. portDict.update({'needTime': needTime})
  528. elif billingType == 'elec':
  529. portDict.update({'needElec': needTime})
  530. elif billingType == "power":
  531. portDict.update({'leftMoney': coins})
  532. Device.update_dev_control_cache(self._device['devNo'], {str(chargeIndex): portDict})
  533. result["finishedTime"] = finishedTime
  534. return result
  535. elif devStatus["portStatusDict"][chargeIndex]['status'] == Const.DEV_WORK_STATUS_WORKING:
  536. result = self._update_charge_balance(port, balance)
  537. portDict = {
  538. "coins": result.get("newBalance")
  539. }
  540. Device.update_dev_control_cache(self._device['devNo'], {str(chargeIndex): portDict})
  541. return result
  542. else:
  543. raise ServiceException(
  544. {'result': 2, 'description': u'车辆未连接,请先连接车辆!'})
  545. def get_port_status_from_dev(self):
  546. result = self._get_device_status_info()
  547. portDict = result["portStatusDict"]
  548. allPorts, usedPorts, usePorts = self.get_port_static_info(portDict)
  549. Device.update_dev_control_cache(self._device['devNo'],
  550. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  551. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  552. for strPort, info in portDict.items():
  553. if ctrInfo.has_key(strPort):
  554. ctrInfo[strPort].update({'status': info['status']})
  555. else:
  556. ctrInfo[strPort] = info
  557. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  558. return result
  559. def set_device_function_param(self, request, lastSetConf):
  560. minPower = request.POST.get("minPower")
  561. checkTime = request.POST.get("checkTime")
  562. powerFailureTime = request.POST.get("powerFailureTime")
  563. checkAutoStop = request.POST.get("checkAutoStop")
  564. floatTime = request.POST.get("floatTime")
  565. price = request.POST.get("price")
  566. overloadPower = request.POST.get("overloadPower")
  567. onceChargeTime = request.POST.get("onceChargeTime")
  568. temperatureTreshold = request.POST.get("temperatureTreshold")
  569. packages = request.POST.get('packages')
  570. powerPrice = {}
  571. for i in range(len(packages)):
  572. powerPrice[str(i)] = packages[i]
  573. lastSetConf.update(
  574. {
  575. "minPower": minPower,
  576. "checkTime": checkTime,
  577. "powerFailureTime": powerFailureTime,
  578. "checkAutoStop": checkAutoStop,
  579. "floatTime": floatTime,
  580. "price": price,
  581. "overloadPower": overloadPower,
  582. "onceChargeTime": onceChargeTime,
  583. "temperatureTreshold": temperatureTreshold,
  584. "powerPrice": powerPrice,
  585. }
  586. )
  587. self._remote_set_device_function_parameter(lastSetConf)
  588. billingType = request.POST.get("billingType")
  589. sound = request.POST.get('sound')
  590. self.device.update_device_obj(**{
  591. 'otherConf.billingType': billingType,
  592. 'otherConf.sound': sound,
  593. 'otherConf.onceChargeTime': onceChargeTime,
  594. 'otherConf.price': price
  595. })
  596. if sound == '0':
  597. soundData = 'EO'
  598. elif sound == '1':
  599. soundData = 'E1'
  600. elif sound == '2':
  601. soundData = 'E2'
  602. elif sound == '3':
  603. soundData = 'E3'
  604. elif sound == '4':
  605. soundData = 'E4'
  606. elif sound == '5':
  607. soundData = 'E5'
  608. elif sound == '6':
  609. soundData = 'E6'
  610. elif sound == '7':
  611. soundData = 'E7'
  612. self._set_sound(soundData)
  613. def get_dev_setting(self):
  614. result = self._remote_get_dev_setting()
  615. return result
  616. def stop_charging_port(self, port=None):
  617. if not port:
  618. raise ServiceException({"result": 2, "description": u"请选择需要结束的充电端口"})
  619. return self._stop_remote(port)
  620. def _response_data(self, cmd, data):
  621. self._send_mqtt(cmd, data)
  622. def get_port_status(self, force=False):
  623. if force:
  624. return self.get_port_status_from_dev()["portStatusDict"]
  625. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  626. if 'allPorts' in ctrInfo and ctrInfo['allPorts'] > 0:
  627. allPorts = ctrInfo['allPorts']
  628. else:
  629. allPorts = 10
  630. statusDict = {}
  631. for ii in range(allPorts):
  632. tempDict = ctrInfo.get(str(ii + 1), {})
  633. if tempDict.has_key('status'):
  634. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  635. elif tempDict.has_key('isStart'):
  636. if tempDict['isStart']:
  637. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  638. else:
  639. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  640. else:
  641. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  642. return statusDict
  643. def active_deactive_port(self, chargeIndex, active):
  644. if active:
  645. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  646. port = int(chargeIndex) - 1
  647. self.stop_charging_port(str(port))
  648. devInfo = Device.get_dev_control_cache(self._device['devNo'])
  649. portCtrInfo = devInfo.get(str(chargeIndex), {})
  650. portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE, 'needTime': 0, 'leftTime': 0,
  651. 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  652. newValue = {str(chargeIndex): portCtrInfo}
  653. Device.update_dev_control_cache(self._device['devNo'], newValue)
  654. def get_port_info(self, chargeIndex):
  655. port = int(chargeIndex) - 1
  656. portHex = fill_2_hexByte(hex(int(port)), 2)
  657. result = self._send_mqtt('A5', data=portHex)
  658. data = result['data']
  659. deviceCode = int(reverse_hex(data[2:8]), 16)
  660. port = int(data[8:10], 16)
  661. orderNo = int(reverse_hex(data[10:20]), 16)
  662. outputVoltage = float(int(reverse_hex(data[20:24]), 16)) / 100
  663. outputElec = float(int(reverse_hex(data[24:28]), 16)) / 1000
  664. power = float(int(reverse_hex(data[28:34]), 16)) / 1000
  665. usedElec = float(int(reverse_hex(data[34:40]), 16)) / 1000
  666. usedMoney = float(int(reverse_hex(data[40:42]), 16)) / 100
  667. cacheInfo = Device.get_dev_control_cache(self.device.devNo)
  668. lineInfo = cacheInfo[chargeIndex]
  669. startTime = datetime.datetime.strptime(lineInfo['startTime'], '%Y-%m-%d %H:%M:%S')
  670. startTime = int(time.mktime(startTime.timetuple()))
  671. nowTime = time.time()
  672. data = {"port": chargeIndex, "power": power, 'elec': usedElec, 'consumeMoney': usedMoney, \
  673. 'outputVoltage': outputVoltage, 'outputElec': outputElec}
  674. if "needTime" in lineInfo:
  675. needTime = lineInfo['needTime']
  676. leftTime = int(needTime - (nowTime - startTime) / 60)
  677. data.update({"needTime":needTime,"leftTime":leftTime})
  678. elif "needElec" in lineInfo:
  679. needElec = lineInfo['needElec']
  680. leftElec = float(needElec) - usedElec
  681. data.update({"needElec": needElec, "leftElec": leftElec})
  682. elif "leftMoney" in lineInfo:
  683. leftMoney = float(lineInfo['leftMoney']) - usedMoney
  684. data.update({"leftMoney": leftMoney})
  685. return data