ywt_chongdiangui_new.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import sys
  5. import time
  6. import logging
  7. from typing import TYPE_CHECKING
  8. from apilib.monetary import RMB, VirtualCoin
  9. from apilib.utils_string import make_title_from_dict
  10. from apps.web.constant import DeviceCmdCode, Const
  11. from apps.web.core.exceptions import ServiceException
  12. from apps.web.eventer import EventBuilder
  13. from apps.web.device.models import Device, Group
  14. from apps.web.eventer.base import FaultEvent, WorkEvent
  15. from apps.web.user.models import ServiceProgress, CardRechargeOrder, ConsumeRecord, CardConsumeRecord, MyUser, \
  16. MonthlyPackage
  17. from apps.common.utils import int_to_hex
  18. from apps.web.core.device_define.ywt_chongdiangui_new import DefaultParams, Calculater
  19. logger = logging.getLogger(__name__)
  20. if TYPE_CHECKING:
  21. from apps.web.core.adapter.ywt_chongdiangui_new import ChargeCabinet
  22. from apps.web.user.models import Card
  23. class builder(EventBuilder):
  24. def __getEvent__(self, device_event):
  25. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  26. if event_data is None or 'cmdCode' not in event_data:
  27. return None
  28. # 粤万通的版本比较复杂 没有一个统一的版本 这次力争升级到一个统一的版本
  29. # TODO 补丁
  30. if "ack_id" in device_event and self.device.driverVersion not in [
  31. "v1.0.0", "v1.0.1", "v1.0.2", "v3.0.1", "v3.0.2", "v3.0.3", "v4.0.0", "v4.0.1"
  32. ]:
  33. self.deviceAdapter._ack(device_event["ack_id"])
  34. cmdCode = event_data.get("cmdCode", "")
  35. className = "ChargeCabinetEvent{}".format(cmdCode.capitalize())
  36. myClass = getattr(sys.modules[__name__], className, None)
  37. if myClass:
  38. logger.info("receive message for dev <{}>\n {}".format(self.deviceAdapter.device.devNo, event_data))
  39. return myClass(self.deviceAdapter, event_data)
  40. # 工具类
  41. class ChargeCabinetEventBase(object):
  42. def stage_billing(self, devNo, port, orderNo, **kwargs):
  43. """每次能够计费的时候 调用该函数计费"""
  44. self.device_adapter._stage_billing(devNo, port, orderNo, **kwargs)
  45. def is_start_by_card(self, port):
  46. devCache = Device.get_dev_control_cache(self.device_adapter.device.devNo)
  47. return "cardNo" in devCache.get(port, dict())
  48. @property
  49. def device_adapter(self):
  50. # type:()->ChargeCabinet
  51. return getattr(self, 'deviceAdapter')
  52. @staticmethod
  53. def reverse_hex(s):
  54. if len(s) == 0:
  55. return ""
  56. return s[-2:] + ChargeCabinetEventBase.reverse_hex(s[:-2])
  57. def response_card_start(self, _type, portStrHex, cardNoHex, balance=0, orderNo="0", chargeTime=0, pw=0, cardType=0, leftDays=0):
  58. balance = ChargeCabinetEventBase.reverse_hex("{:0>8X}".format(int(balance * 100) & 0xFFFFFFFF))
  59. cardType = ChargeCabinetEventBase.reverse_hex("{:0>2X}".format(int(cardType)))
  60. leftDays = ChargeCabinetEventBase.reverse_hex("{:0>4X}".format(int(leftDays)))
  61. orderNo = ChargeCabinetEventBase.reverse_hex("{:0>14X}".format(int(orderNo)))
  62. chargeTime = ChargeCabinetEventBase.reverse_hex("{:0>4X}".format(int(chargeTime)))
  63. pw = ChargeCabinetEventBase.reverse_hex("{:0>4X}".format(int(pw)))
  64. sendData = cardNoHex + portStrHex + _type + balance + cardType + leftDays + orderNo + chargeTime + pw
  65. self.device_adapter._send_data(funCode="B0", sendData=sendData, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  66. def response_finish(self, orderNoHex, portStr):
  67. portStrHex = int_to_hex(portStr, lens=2)
  68. sendData = orderNoHex + portStrHex + "01"
  69. self.device_adapter._send_data("C1", sendData, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  70. def response_fault(self, port):
  71. portStrHex = "{:02X}".format(port)
  72. sendData = portStrHex + "01"
  73. self.device_adapter._send_data("E0", sendData, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  74. def response_card_finish(self, cardNoHex, portStrHex, balance, consumeMoney, cardType=1, leftDays=0, cardStatus="01"):
  75. balanceHex = ChargeCabinetEventBase.reverse_hex("{:0>8X}".format(int(balance*100)))
  76. consumeMoneyHex = ChargeCabinetEventBase.reverse_hex("{:0>8X}".format(int(consumeMoney*100)))
  77. cardTypeHex = ChargeCabinetEventBase.reverse_hex("{:0>2X}".format(int(cardType)))
  78. leftDaysHex = ChargeCabinetEventBase.reverse_hex("{:0>4X}".format(int(leftDays)))
  79. sendData = cardNoHex + portStrHex + cardStatus + balanceHex + cardTypeHex + leftDaysHex + consumeMoneyHex
  80. self.device_adapter._send_data("B1", sendData, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  81. def deduct_for_card(self, portStr, card, money, consumeOrder, cardConsumeOrder):
  82. devCache = Device.get_dev_control_cache(self.device_adapter.device.devNo)
  83. portCache = devCache.get(portStr)
  84. monthlyPackageId = portCache.get("monthlyPackageId")
  85. if monthlyPackageId:
  86. monthlyPackage = MonthlyPackage.objects.get(id=monthlyPackageId)
  87. monthlyPackage.deduct(consumeOrder)
  88. else:
  89. cardBalance = card.balance - RMB(money)
  90. card.balance = cardBalance
  91. card.save()
  92. # 更新
  93. consumeOrder.update(money=RMB(money).mongo_amount, coin=VirtualCoin(money).mongo_amount, status="finished")
  94. cardConsumeOrder.update(money=RMB(money).mongo_amount, coin=VirtualCoin(money).mongo_amount)
  95. # 故障
  96. class ChargeCabinetEventE0(FaultEvent, ChargeCabinetEventBase):
  97. def do(self, **args):
  98. group = Group.get_group(self.device["groupId"])
  99. if self.is_notify_dealer():
  100. self.notify_dealer(
  101. "device_fault",
  102. title=u"注意注意您的设备发生故障",
  103. device=u"组号:{},二维码编号:{}".format(self.device["groupNumber"], self.device["logicalCode"]),
  104. location=u"组名称:{},地址:{}".format(group["groupName"], group["address"]),
  105. fault=self.event_data["statusInfo"],
  106. notifyTime=str(datetime.datetime.now())[:19]
  107. )
  108. warningData = {
  109. "warningStatus": 2,
  110. "warningDesc": self.event_data["statusInfo"],
  111. "warningTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  112. }
  113. # 整机告警
  114. part = self.event_data.get("portStr", "0")
  115. Device.update_dev_warning_cache(self.device.devNo, {part: warningData})
  116. try:
  117. faultRecord = self.record(
  118. faultCode=self.event_data.get("faultCode", ""),
  119. detail={"errorCode": self.event_data["faultCode"]}
  120. )
  121. self.north_to_liangxi(faultRecord)
  122. except Exception as e:
  123. logger.error(e)
  124. finally:
  125. sendData = self.event_data.get("portHex") + "01"
  126. self.deviceAdapter._send_data("E0", sendData=sendData, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  127. # 时间同步
  128. class ChargeCabinetEventA1(WorkEvent, ChargeCabinetEventBase):
  129. def do(self, **args):
  130. logger.info("charge cabinet <{}> request to synchronization time".format(self.device.devNo))
  131. self.deviceAdapter._sync_device_time()
  132. # 参数设置同步
  133. class ChargeCabinetEventA2(WorkEvent, ChargeCabinetEventBase):
  134. def do(self, **args):
  135. logger.info("charge cabinet <{}> request to device params".format(self.device.devNo))
  136. self.deviceAdapter._sync_device_settings()
  137. # 刷卡上报
  138. class ChargeCabinetEventB0(WorkEvent, ChargeCabinetEventBase):
  139. def do(self, **args):
  140. """
  141. 两个问题 刷卡的时候主板会判断当前端口是否已经被占用
  142. :param args:
  143. :return:
  144. """
  145. logger.info("charge cabinet <{}> send a card <{}> start signal ".format(self.device.devNo, self.event_data.get("cardNo", "error cardNo")))
  146. cardNo = self.event_data.get("cardNo")
  147. portStr = self.event_data.get("portStr")
  148. portStrHex = self.event_data['portHex']
  149. cardNoHex = self.event_data['cardNoHex']
  150. lockPorts = self.device.otherConf.get("lockPorts") or list()
  151. if portStr in lockPorts:
  152. self.response_card_start(_type="03", portStrHex=portStrHex, cardNoHex=cardNoHex)
  153. return
  154. card = self.update_card_dealer_and_type(cardNo) # type: Card
  155. # 粤万通的要求 不同地址的卡不可以通用
  156. if not card or card.frozen or not card.openId and card.groupId != self.device.groupId:
  157. self.response_card_start(_type="03", portStrHex=portStrHex, cardNoHex=cardNoHex)
  158. logger.info("bad card, cardNo is %s, cannot start port!" % cardNo)
  159. return
  160. # 充值未到账的卡的处理 有些卡充值在没有上报类型之前 充值结果不会到账的 这个地方需要处理一下
  161. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  162. self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order)
  163. card.reload()
  164. # 判断是否可以使用包月卡启动设备, 有包月卡并且可用的 不在进行余额的判断, 不在进行设备类型的判断
  165. monthlyPackage = card.monthlyPackage
  166. if monthlyPackage:
  167. cardType = 2
  168. leftDays = (monthlyPackage.expireDateTime - datetime.datetime.now()).days
  169. else:
  170. # 能够刷卡的最低的金额
  171. minCardMoney = self.device.get("otherConf", dict()).get("minAfterStartCoins", DefaultParams.DEFAULT_MIN_START_COINS)
  172. if float(card.balance) < float(minCardMoney):
  173. self.response_card_start(_type="02", portStrHex=portStrHex, cardNoHex=cardNoHex, balance=card.balance)
  174. logger.info("negative card, card No is %s, card balance is %s" % (cardNo, card.balance))
  175. return
  176. cardType = 1
  177. leftDays = 0
  178. # 制造启动前的各种参数 密码 时间等等
  179. chargeTime = 0xFFFF
  180. pw = self.deviceAdapter.password
  181. try:
  182. otherConf = self.device.get("otherConf")
  183. servicedInfo = {"pw": pw, "chargeType": otherConf.get("chargeType", DefaultParams.DEFAULT_CHARGE_TYPE)}
  184. orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(0), desc="刷卡消费", attachParas={"pw": pw}, servicedInfo=servicedInfo)
  185. except Exception as e:
  186. logger.error("record to database error!".format(e))
  187. return
  188. # 返回刷卡 OK 的信息
  189. self.response_card_start(
  190. "01",
  191. portStrHex,
  192. cardNoHex=cardNoHex,
  193. balance=card.balance,
  194. orderNo=orderNo,
  195. chargeTime=chargeTime,
  196. pw=pw,
  197. cardType=cardType,
  198. leftDays=leftDays
  199. )
  200. logger.info("card start ok! event has been report!")
  201. # 支持发送关门自动断电的 发送新指令
  202. if self.deviceAdapter.is_support_auto_charge:
  203. self.deviceAdapter._new_charge(orderNo=orderNo, port=portStr, pw=pw)
  204. # 否则由服务器控制充电
  205. else:
  206. self.deviceAdapter._open(orderNo=orderNo, port=portStr, pw=pw)
  207. # 启动设备之后,注册服务,并更新端口缓存值
  208. ServiceProgress.register_card_service(
  209. self.device,
  210. int(portStr),
  211. card,
  212. {
  213. "orderNo": orderNo,
  214. "cardOrderNo": cardOrderNo
  215. },
  216. finishedTime=int(time.time()) + 7 * 24 * 60 * 60
  217. )
  218. portDict = {
  219. "status": Const.DEV_WORK_STATUS_WORKING,
  220. "isStart": True,
  221. "orderNo": orderNo,
  222. "cardOrderNo": cardOrderNo,
  223. "cardNo": cardNo,
  224. "openId": card.openId,
  225. "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  226. "pw": pw,
  227. "monthlyPackageId": None if cardType == 1 else str(monthlyPackage.id)
  228. }
  229. self.notify_user(
  230. managerialOpenId=card.managerialOpenId,
  231. templateName="consume_notify",
  232. title=u"您正在刷卡启动充电柜业务",
  233. money=u"使用结束后计算费用",
  234. serviceType=u"刷卡消费, 当前启动为: {}柜门".format(portStr),
  235. finishTime=datetime.datetime.now().strftime(Const.DATETIME_FMT)
  236. )
  237. Device.update_dev_control_cache(self.device["devNo"], {portStr: portDict})
  238. # 刷卡结束上报
  239. class ChargeCabinetEventB1(WorkEvent, ChargeCabinetEventBase):
  240. def do(self, **args):
  241. """
  242. 刷卡结束的时候, 仅仅会接受到刷卡上报的信息 和主板商沟通过不会再有充电结束的上报
  243. :return:
  244. """
  245. portStrHex = self.event_data['portHex']
  246. cardNoHex = self.event_data['cardNoHex']
  247. cardNo = self.event_data.get("cardNo")
  248. portStr = self.event_data.get("portStr")
  249. orderNo = self.event_data.get("orderNo")
  250. devCache = Device.get_dev_control_cache(self.device.devNo)
  251. portCache = devCache.get(portStr) or dict()
  252. if not portCache:
  253. logger.error("no port cache, error card finished!, card is <{}>".format(cardNo))
  254. self.response_card_finish(cardNoHex, portStrHex, cardStatus="03")
  255. return
  256. if cardNo != portCache.get("cardNo"):
  257. logger.error("card no is not equal , card is <{}>".format(cardNo))
  258. self.response_card_finish(cardNoHex, portStrHex, cardStatus="03")
  259. return
  260. pw = portCache.get("pw", "")
  261. cardOrderNo = portCache.get("cardOrderNo", "")
  262. try:
  263. card = self.update_card_dealer_and_type(cardNo)
  264. consumeOrder = ConsumeRecord.objects.get(orderNo=orderNo)
  265. cardConsumeOrder = CardConsumeRecord.objects.get(orderNo=cardOrderNo)
  266. except Exception as e:
  267. logger.exception(e)
  268. return
  269. # 请求结束充电 发送
  270. result = self.deviceAdapter._stop(portStr, orderNo, pw, door=True)
  271. data = result.get("data")
  272. curInfo = self.deviceAdapter._parse_result_B2(data)
  273. curInfo.update({"orderNo": orderNo})
  274. # 记录最后一次的上报 然后获取订单的金额
  275. self.deviceAdapter._stage_billing(self.device.devNo, portStr, **curInfo)
  276. consumeMoney = Calculater.get_consume_by_order(self.device, orderNo)
  277. # 刷卡计费
  278. self.deduct_for_card(portStr, card, consumeMoney, consumeOrder, cardConsumeOrder)
  279. # 结束服务
  280. consumeDict = {
  281. "chargeIndex": portStr,
  282. 'actualNeedTime': curInfo.get("chargeTime"),
  283. 'elec': curInfo.get("elec"),
  284. 'stayTime': curInfo.get("stayTime"),
  285. 'chargeTime': curInfo.get("chargeTime"),
  286. }
  287. ServiceProgress.update_progress_and_consume_rcd(
  288. self.device["ownerId"],
  289. {
  290. "cardId": str(card.id),
  291. "open_id": consumeOrder.openId,
  292. "device_imei": self.device["devNo"],
  293. "port": int(portStr),
  294. "isFinished": False
  295. },
  296. consumeDict
  297. )
  298. monthlyPackageId = portCache.get("monthlyPackageId")
  299. if monthlyPackageId:
  300. monthlyPackage = MonthlyPackage.objects.get(id=monthlyPackageId)
  301. self.response_card_finish(
  302. cardNoHex=cardNoHex,
  303. portStrHex=portStrHex,
  304. balance=RMB(0),
  305. consumeMoney=RMB(consumeMoney),
  306. cardType=2,
  307. leftDays=max((monthlyPackage.expireDateTime - datetime.datetime.now()).days, 0)
  308. )
  309. extra = [({"消费金额": "{}元".format(consumeMoney), "余额": "{}元".format(0)})]
  310. else:
  311. self.response_card_finish(
  312. cardNoHex=cardNoHex,
  313. portStrHex=portStrHex,
  314. balance=RMB(card.balance),
  315. consumeMoney=RMB(consumeMoney)
  316. )
  317. extra=[({"消费金额": "{}元".format(consumeMoney), "余额": "{}元".format(card.balance)})]
  318. self.notify_user_service_complete(
  319. service_name='充电',
  320. openid=card.managerialOpenId,
  321. port=portStr,
  322. address=self.device.group['address'],
  323. reason=self.event_data.get('reasonDesc'),
  324. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  325. extra=extra)
  326. Device.clear_port_control_cache(self.device.devNo, portStr)
  327. # 充电结束上报 一般是充满电了
  328. class ChargeCabinetEventC1(WorkEvent, ChargeCabinetEventBase):
  329. def do(self, **args):
  330. orderNo = self.event_data.get("orderNo")
  331. portStr = self.event_data.get("portStr")
  332. devCache = Device.get_dev_control_cache(self.device["devNo"])
  333. portCache = devCache.get(portStr, dict())
  334. openId = portCache.get("openId")
  335. if not orderNo or not openId:
  336. logger.info("device {} port {} report event, useless info!\n{}".format(self.device["devNo"], portStr, self.event_data))
  337. return
  338. portCache.update({
  339. "status": Const.DEV_WORK_STATUS_OCCUPY, # 状态更新进入占位状态
  340. "voltage": self.event_data.get("voltage"),
  341. "power": self.event_data.get("power"),
  342. "elec": self.event_data.get("elec"),
  343. "chargeTime": self.event_data.get("chargeTime"),
  344. "stayTime": self.event_data.get("stayTime"),
  345. "temperature": self.event_data.get("temperature")
  346. })
  347. Device.update_dev_control_cache(self.device.devNo, {portStr: portCache})
  348. # 计费记账
  349. self.stage_billing(self.device.devNo, portStr, **self.event_data)
  350. # 密码开锁的,说明单已经结束 直接调用消费订单的状态机结束订单就好
  351. if self.event_data.get("reasonCode") == "06":
  352. totalConsume = Calculater.get_consume_by_order(self.device, orderNo)
  353. order = ConsumeRecord.objects.get(orderNo=orderNo)
  354. consumeDict = {
  355. "chargeIndex": portStr,
  356. 'actualNeedTime': self.event_data.get("chargeTime"),
  357. 'elec': self.event_data.get("elec"),
  358. 'stayTime': self.event_data.get("stayTime"),
  359. 'chargeTime': self.event_data.get("chargeTime"),
  360. }
  361. if order.servicedInfo.get('chargeType') == 'elec':
  362. elec_charge, service_charge = self.deviceAdapter.calc_elecFee_and_serviceFee(totalConsume)
  363. consumeDict.update({
  364. 'elecCharge': elec_charge.mongo_amount,
  365. 'serviceCharge': service_charge.mongo_amount,
  366. })
  367. if self.is_start_by_card(portStr):
  368. cardNo = portCache.get("cardNo")
  369. card = self.update_card_dealer_and_type(cardNo)
  370. # 扣钱 然后记账
  371. orderNo = portCache.get("orderNo", "")
  372. cardOrderNo = portCache.get("cardOrderNo", "")
  373. cardConsumeOrder = CardConsumeRecord.objects.get(orderNo=cardOrderNo)
  374. consumeOrder = ConsumeRecord.objects.get(orderNo=orderNo)
  375. self.deduct_for_card(portStr, card, totalConsume, consumeOrder, cardConsumeOrder)
  376. else:
  377. try:
  378. order.update(money=RMB(totalConsume).mongo_amount, coin=VirtualCoin(totalConsume).mongo_amount)
  379. order.reload()
  380. order.s_to_e()
  381. except Exception as e:
  382. logger.error("finished order <{}> error {}\n {}".format(orderNo, e, self.event_data))
  383. ServiceProgress.update_progress_and_consume_rcd(
  384. self.device["ownerId"],
  385. {
  386. "open_id": openId,
  387. "device_imei": self.device.devNo,
  388. "port": int(portStr),
  389. "isFinished": False
  390. },
  391. consumeDict
  392. )
  393. Device.clear_port_control_cache(self.device.devNo, portStr)
  394. # 开始通知用户充电结束 进入占位状态
  395. else:
  396. user = MyUser.objects.filter(openId=portCache.get("openId"), groupId=self.device["groupId"]).first()
  397. extra = [
  398. {u'结束原因': u'{}'.format(self.event_data["reason"])},
  399. {u'设备编号': u'{}-{}'.format(self.device["logicalCode"], portStr)},
  400. {u"服务地址": u"{}".format(self.device.group["address"])},
  401. {u"充电时间": u"{}分钟".format(self.event_data["chargeTime"])},
  402. ]
  403. title = make_title_from_dict(extra)
  404. self.notify_user(
  405. managerialOpenId=user.managerialOpenId if user else "",
  406. templateName="service_complete",
  407. title=title,
  408. service=u"充电桩充电服务",
  409. finishTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  410. remark=u'充电已经结束,请及时取走您的电池!'
  411. )
  412. # 状态上报
  413. class ChargeCabinetEventC0(WorkEvent, ChargeCabinetEventBase):
  414. def do(self, **args):
  415. orderNo = self.event_data.get("orderNo")
  416. portStr = self.event_data.get("portStr")
  417. devCache = Device.get_dev_control_cache(self.device["devNo"])
  418. portCache = devCache.get(portStr, dict())
  419. openId = portCache.get("openId")
  420. if not orderNo or not openId:
  421. logger.error("device {} port {} report event, useless info!\n{}".format(self.device["devNo"], portStr, self.event_data))
  422. return
  423. portCache.update({
  424. "voltage": self.event_data.get("voltage"),
  425. "power": self.event_data.get("power"),
  426. "elec": self.event_data.get("elec"),
  427. "usedTime": self.event_data.get("chargeTime"),
  428. "occTime": self.event_data.get("stayTime"),
  429. "temperature": self.event_data.get("temperature")
  430. })
  431. Device.update_dev_control_cache(self.device.devNo, {portStr: portCache})
  432. # 取出last之后 然后再将现在的保存下来
  433. self.stage_billing(self.device.devNo, portStr, **self.event_data)
  434. # 门锁状态 上报
  435. class ChargeCabinetEventC3(WorkEvent, ChargeCabinetEventBase):
  436. def do(self, **args):
  437. portStr = self.event_data.get("portStr")
  438. doorStatus = self.event_data.get("doorStatus")
  439. if doorStatus == DefaultParams.CLOSE_LOCK:
  440. self._do_door_close(portStr)
  441. else:
  442. self._do_door_open(portStr)
  443. def _do_door_close(self, portStr):
  444. devCache = Device.get_dev_control_cache(self.device.devNo)
  445. portCache = devCache.get(portStr, dict())
  446. # 已经发过一次充电指令的
  447. if "hasStartCharge" in portCache:
  448. return
  449. pw = portCache.get("pw")
  450. orderNo = portCache.get("orderNo")
  451. openId = portCache.get("openId")
  452. if not all([pw, orderNo, openId]):
  453. logger.info(u"useless lock close\n<{}>\n<{}>".format(self.deviceAdapter.device.devNo, self.event_data))
  454. return
  455. group = Group.get_group(self.device["groupId"])
  456. user = MyUser.objects.filter(openId=openId, groupId=self.device.groupId).first()
  457. if not self.deviceAdapter.is_support_auto_charge:
  458. try:
  459. self.deviceAdapter._charge(portStr, orderNo, pw)
  460. except ServiceException:
  461. isCharge = False
  462. else:
  463. isCharge = True
  464. else:
  465. isCharge = True
  466. if not isCharge:
  467. self.notify_user(
  468. managerialOpenId=user.managerialOpenId if user else "",
  469. templateName="service_complete",
  470. title=u"\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}".format(
  471. logicalCode=self.device["logicalCode"],
  472. port=self.event_data["portStr"],
  473. group=group["address"],
  474. ),
  475. service=u"充电柜服务",
  476. finishTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  477. remark=u'充电开启失败,请扫码重新启动充电或取走电池!'
  478. )
  479. else:
  480. extra = [
  481. {u"设备编号": u"{}-{}".format(self.device["logicalCode"], portStr)},
  482. {u"服务地址": u"{}".format(self.device.group["address"])},
  483. {u"开门密码": u"{}".format(pw)},
  484. ]
  485. title = make_title_from_dict(extra)
  486. self.notify_user(
  487. managerialOpenId=user.managerialOpenId if user else "",
  488. templateName="service_complete",
  489. title=title,
  490. service=u"充电柜服务",
  491. finishTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  492. remark=u'已成功为您开启充电,感谢您的使用!'
  493. )
  494. def _do_door_open(self, portStr):
  495. """测试的时候发现 好像只有非指令开锁 才会存在门锁状态打开的上报"""
  496. # TODO 尚需证实
  497. # group = Group.get_group(self.device["groupId"])
  498. #
  499. # self.notify_dealer(
  500. # templateName="device_fault",
  501. # title="注意!设备异常",
  502. # device=u"{groupNumber}组-{logicalCode}".format(
  503. # groupNumber=self.device["groupNumber"],
  504. # logicalCode=self.device["logicalCode"]
  505. # ),
  506. # location=u"{address}-{groupName}".format(address=group["address"], groupName=group["groupName"]),
  507. # fault=u"门锁异常打开",
  508. # notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  509. # )
  510. class ChargeCabinetEventCa(WorkEvent, ChargeCabinetEventBase):
  511. def do(self, **args):
  512. logger.info("device <{}> receive CA, event data = {}".format(self.device.devNo, self.event_data))
  513. subChargeList = self.event_data["subChargeList"]
  514. for _sub in subChargeList:
  515. ChargeCabinetEventC0(self.deviceAdapter, _sub).do()