hangxin.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import logging
  4. import time
  5. from apilib.utils_datetime import timestamp_to_dt
  6. from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const
  7. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte
  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. logger = logging.getLogger(__name__)
  12. class FuncCode(object):
  13. # 发送设备事件
  14. GET_PORT_INFO = "01"
  15. START_DEV = "02"
  16. class HangXinBox(SmartBox):
  17. AUTO_STOP_COINS_MOTO = 250 # 摩托充满自停的金币数量
  18. AUTO_STOP_COINS_CAR = 1000 # 汽车充满自停的金币数量
  19. MIN_RECHARGE_MONEY = 20
  20. QUOTA_ELEC = 500
  21. WARNING_ELEC = 30
  22. SEND_DATA = "{funCode}{sendData}000000"
  23. PORT_MAP = {
  24. "1": "A1",
  25. "2": "A2",
  26. "3": "A3",
  27. "4": "A4",
  28. "5": "A5",
  29. "6": "A6",
  30. "7": "A7",
  31. "8": "A8",
  32. "9": "A9",
  33. "10": "A0",
  34. }
  35. PORT_STR_MAP = {v: k for k, v in PORT_MAP.items()}
  36. def __sendData(self, funCode, sendData = "0000", portStr = None, timeout = MQTT_TIMEOUT.NORMAL, orderNo = None):
  37. if portStr is None and funCode == FuncCode.GET_PORT_INFO:
  38. sendPort = "FA" # 全部的端口状态查询
  39. else:
  40. if not HangXinBox.PORT_MAP.has_key(portStr): raise ServiceException({'result': 2, 'description': u'无效的端口号'})
  41. sendPort = HangXinBox.PORT_MAP[portStr]
  42. data = self.SEND_DATA.format(funCode = funCode, sendData = sendData)
  43. result = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  44. payload = {"IMEI": self._device["devNo"], "funCode": sendPort, "data": data},
  45. timeout = timeout)
  46. if result.has_key("rst") and result["rst"] != 0:
  47. if result['rst'] == -1:
  48. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请稍候再试'})
  49. elif result['rst'] == 1:
  50. raise ServiceException({'result': 2, 'description': u'充电桩主板连接故障'})
  51. else:
  52. raise ServiceException({'result': 2, 'description': u'系统错误'})
  53. return result
  54. @staticmethod
  55. def __parse_port_data(data):
  56. portStr = HangXinBox.PORT_STR_MAP.get(data[: 2])
  57. statusBytes = data[2: 4]
  58. tempData = {
  59. "portStr": portStr,
  60. "statusBytes": statusBytes
  61. }
  62. elecNum = int(data[4: 8], 16)
  63. # 解析端口状态 若是存在剩余电量 添加入解析信息
  64. if statusBytes == "04":
  65. status = Const.DEV_WORK_STATUS_FAULT
  66. elif statusBytes == "07":
  67. if elecNum:
  68. status = Const.DEV_WORK_STATUS_WORKING
  69. tempData.update({"elecNum": str(elecNum)})
  70. else:
  71. status = Const.DEV_WORK_STATUS_IDLE
  72. else:
  73. status = None
  74. tempData.update({"status": status})
  75. return tempData
  76. def __get_one_port_info(self, port):
  77. result = self.__sendData(FuncCode.GET_PORT_INFO, portStr = port)
  78. return self.__parse_port_data(result.get("data"))
  79. def analyze_event_data(self, data):
  80. portStr = HangXinBox.PORT_STR_MAP.get(data[: 2])
  81. if not portStr:
  82. return
  83. elecNum = str(int(data[4: 8], 16))
  84. chargeStatus = data[8: 10]
  85. if chargeStatus == "01":
  86. desc = u"电量已经充满"
  87. elif chargeStatus == "02":
  88. desc = u"充电结束"
  89. elif chargeStatus == "03":
  90. desc = u"充电结束"
  91. else:
  92. desc = ""
  93. logger.error("undefined chargeStatus is %s" % chargeStatus)
  94. return {"leftElec": elecNum, "portStr": portStr, "chargeStatus": chargeStatus, "desc": desc}
  95. def start_device(self, package, openId, attachParas):
  96. if not isinstance(attachParas, dict):
  97. raise ServiceException({"result": 2, "description": u"请选择合适的充电桩"})
  98. port = attachParas.get("chargeIndex", None)
  99. if not port:
  100. raise ServiceException({'result': 2, 'description': u"请选择合适的充电桩"})
  101. portStr = str(port)
  102. # 获取启动设备的金币
  103. coins = int(package['coins'])
  104. hexCoins = fill_2_hexByte(hex(coins), 4)
  105. orderNo = attachParas.get('orderNo')
  106. # 启动设备 对于此协议如果此端口有负载则不会响应 mqtt超时
  107. result = self.__sendData(FuncCode.START_DEV, sendData = hexCoins, portStr = portStr,
  108. timeout = MQTT_TIMEOUT.START_DEVICE, orderNo = orderNo)
  109. tempStatus = self.__parse_port_data(result.get("data"))
  110. if not tempStatus.get("elecNum"):
  111. raise ServiceException({'result': 2, 'description': u"设备回应端口故障,请试试其他端口"})
  112. start_timestamp = int(time.time())
  113. result["finishedTime"] = start_timestamp + 3600 * 24
  114. portDict = {
  115. 'status': Const.DEV_WORK_STATUS_WORKING,
  116. 'finishedTime': result["finishedTime"],
  117. 'coins': float(coins),
  118. 'isStart': True,
  119. 'openId': openId,
  120. 'vCardId': self._vcard_id,
  121. "needElec": tempStatus.get("elecNum"),
  122. "startTime": timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S')
  123. }
  124. Device.update_dev_control_cache(self._device["devNo"], {str(port): portDict})
  125. return result
  126. def is_port_can_use(self, port, canAdd = False):
  127. port = str(int(port))
  128. portInfo = self.__get_one_port_info(port)
  129. if portInfo:
  130. status = portInfo.get("status", None)
  131. if status == Const.DEV_WORK_STATUS_IDLE:
  132. canUse = True
  133. desc = u""
  134. elif status == Const.DEV_WORK_STATUS_WORKING:
  135. canUse = False
  136. desc = u'该线路正在工作,暂时不能继续使用,请您使用其他线路,或者等待该线路工作完毕'
  137. elif status == Const.DEV_WORK_STATUS_FAULT:
  138. canUse = False
  139. desc = u'该线路故障,暂时不能使用,请您使用其他线路'
  140. elif status == Const.DEV_WORK_STATUS_FORBIDDEN:
  141. canUse = False
  142. desc = u'该线路已被禁用,暂时不能使用,请您使用其他线路'
  143. else:
  144. canUse = False
  145. desc = u'该线路未知状态,暂时不能使用'
  146. else:
  147. canUse = False
  148. desc = u"未知充电端口,无法使用"
  149. return canUse, desc
  150. def get_port_info(self, line = None):
  151. tempStatus = self.__get_one_port_info(line)
  152. elec = tempStatus.get("elecNum")
  153. portInfo = Device.get_dev_control_cache(self._device["devNo"]).get(str(line))
  154. if not portInfo:
  155. logger.error("no port info")
  156. raise ServiceException({'result': 2, 'description': u'暂无端口信息,请稍后再试'})
  157. coins = portInfo.get("coins")
  158. if not coins:
  159. logger.error("port info has no coins info")
  160. # 类型判断是汽车还是摩托车 两种车的类型不同 对应的充满自停的费用不同
  161. if int(coins) == HangXinBox.AUTO_STOP_COINS_MOTO:
  162. data = {"consumeMoney": u"%s币" % str(HangXinBox.AUTO_STOP_COINS_MOTO - int(elec))}
  163. elif int(coins) == HangXinBox.AUTO_STOP_COINS_CAR:
  164. data = {"consumeMoney": u"%s币" % str(HangXinBox.AUTO_STOP_COINS_CAR - int(elec))}
  165. else:
  166. data = {"leftMoney": u"%s币" % elec}
  167. data.update({"leftElec": elec})
  168. return data
  169. def set_device_function_param(self, request, lastSetConf):
  170. minRechargeMoney = request.POST.get("minRechargeMoney")
  171. quotaElec = request.POST.get("quotaElec")
  172. warningElec = request.POST.get("warningElec")
  173. if quotaElec < warningElec:
  174. raise ServiceException({"result": 2, "description": u"设置失败,请确认您的电量余额是否已经小于报警电量"})
  175. if minRechargeMoney:
  176. lastSetConf.update({"minRechargeMoney": minRechargeMoney})
  177. if quotaElec:
  178. lastSetConf.update({"quotaElec": quotaElec})
  179. if warningElec:
  180. lastSetConf.update({"warningElec": warningElec})
  181. Device.objects.filter(devNo = self._device["devNo"]).update(otherConf = lastSetConf)
  182. Device.invalid_device_cache(self._device["devNo"])
  183. def get_dev_setting(self):
  184. dev = Device.objects.get(devNo = self._device["devNo"])
  185. otherConf = dev.otherConf
  186. return {
  187. "minRechargeMoney": otherConf.get("minRechargeMoney", self.MIN_RECHARGE_MONEY),
  188. "quotaElec": otherConf.get("quotaElec", self.QUOTA_ELEC),
  189. "warningElec": otherConf.get("warningElec", self.WARNING_ELEC)
  190. }
  191. @property
  192. def show_pay_unit(self):
  193. return u"金币"