dianchuan.py 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import random
  6. import time
  7. from arrow import Arrow
  8. from django.conf import settings
  9. from typing import TYPE_CHECKING
  10. from apilib.monetary import sum_rmb, RMB, VirtualCoin, Ratio
  11. from apilib.utils_datetime import to_datetime
  12. from apps.web.device.timescale import FluentedEngine
  13. from apps.web.south_intf.liangxi_fire import LiangXiXiaoFang
  14. from apps.web.common.models import District
  15. from apps.web.constant import Const, FAULT_CODE, FAULT_LEVEL, DEALER_CONSUMPTION_AGG_KIND
  16. from apps.web.core.accounting import Accounting
  17. from apps.web.core.device_define.dianchuan import FINISHED_CHARGE_REASON_MAP
  18. from apps.web.dealer.models import Dealer
  19. from apps.web.device.models import PortReport, OfflineCoinStatistics, Part, Group, Device
  20. from apps.web.eventer.base import FaultEvent, WorkEvent, ComNetPayAckEvent, IcStartAckEvent, \
  21. AckEventProcessorIntf, IcRechargeAckEvent, CardRefundAckEvent
  22. from apps.web.eventer import EventBuilder
  23. from apps.web.south_intf.platform import notify_event_to_north
  24. from apps.web.south_intf.zhejiang_fire import send_event_to_zhejiang
  25. from apps.web.user.models import VCardConsumeRecord, ServiceProgress, UserVirtualCard, CardRechargeOrder, MyUser, \
  26. ConsumeRecord, RechargeRecord, Card
  27. if TYPE_CHECKING:
  28. from apps.web.user.models import Card
  29. from apps.web.device.models import GroupDict
  30. from apps.web.device.models import DeviceDict
  31. logger = logging.getLogger(__name__)
  32. class builder(EventBuilder):
  33. def __getEvent__(self, device_event):
  34. if 'data' not in device_event:
  35. return None
  36. if 'type' in device_event:
  37. if device_event['type'] == 'alert':
  38. return DIANCHUANAlertEvent(self.deviceAdapter, device_event)
  39. if device_event['type'] == 'report':
  40. return DIANCHUANReport(self.deviceAdapter, device_event)
  41. else:
  42. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  43. if event_data is None or 'cmdCode' not in event_data:
  44. return None
  45. if 'duration' in device_event:
  46. event_data.update({'duration': device_event['duration']})
  47. if 'elec' in device_event:
  48. event_data.update({'elec': device_event['elec']})
  49. if 'v' in device_event:
  50. event_data.update({'v': device_event['v']})
  51. if 'today_coins' in device_event and 'ts' in device_event:
  52. event_data.update({'today_coins': device_event['today_coins']})
  53. event_data.update({'ts': device_event['ts']})
  54. if event_data.get('cmdCode') in ['03', '05', '11', '12', '17', '22', '48']:
  55. return ChargingDIANCHUANWorkEvent(self.deviceAdapter, event_data)
  56. if event_data.get('cmdCode') == '0D':
  57. return DIANCHUANFaultEvent(self.deviceAdapter, event_data)
  58. if event_data.get('cmdCode') in ['41', '47']:
  59. return DIANCHUANInductorEvent(self.deviceAdapter, event_data)
  60. class ChargingDIANCHUANWorkEvent(WorkEvent):
  61. @property
  62. def support_playback(self):
  63. if self.event_data['cmdCode'] in ['05']:
  64. return True
  65. else:
  66. return False
  67. def __parse_device_finished_data(self, event_data):
  68. duration = event_data.get('duration', -1)
  69. if duration != -1:
  70. if 'v' in event_data:
  71. duration = (duration / 60)
  72. elec = event_data.get('elec', -1)
  73. if elec != -1:
  74. if 'v' in event_data:
  75. elec = round(elec / (10000.0 * 3600.0), 3)
  76. else:
  77. elec = round(elec / 3600.0, 3)
  78. logger.debug('device duration is {}, device elec is {}'.format(duration, elec))
  79. return duration, elec
  80. def do(self, **args):
  81. logger.info('[dianchuan] charging event detected, devNo=%s,info=%s' % (self.device.devNo, self.event_data))
  82. if self.event_data['cmdCode'] == '03':
  83. if 'today_coins' in self.event_data and 'ts' in self.event_data:
  84. Accounting.syncOfflineCoin(
  85. self.device,
  86. datetime.datetime.fromtimestamp(self.event_data['ts']).strftime('%Y-%m-%d'),
  87. self.event_data['today_coins'])
  88. if self.event_data['coins'] > 0:
  89. FluentedEngine().in_put_coins_udp(devNo=self.device.devNo,
  90. ts=int(time.time()),
  91. coins=self.event_data['coins'],
  92. mode='uart')
  93. else:
  94. # 老的流程会单条记录上报记录
  95. Accounting.recordOfflineCoin(device=self.device,
  96. report_ts=int(time.time()),
  97. coins=int(self.event_data['coins']),
  98. mode='uart',
  99. port=self.event_data.get('port', None))
  100. try:
  101. # 如果是投币,直接把端口状态刷新下
  102. self.deviceAdapter.get_port_status_from_dev()
  103. except Exception, e:
  104. logger.info('some err=%s' % e)
  105. # YuhuanNorther.send_dev_status(self.device, self.event_data['port'], 1)
  106. elif self.event_data['cmdCode'] == '22': # ID在线卡刷卡查询余额
  107. cardNo = self.event_data['cardNo']
  108. fee = RMB(self.event_data['fee'])
  109. cardType = self.event_data['cardType']
  110. card = self.update_card_dealer_and_type(cardNo)
  111. if not card:
  112. res = "03"
  113. elif not card.openId:
  114. res = '03'
  115. elif card.frozen:
  116. res = '04'
  117. else:
  118. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  119. result = self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order)
  120. card.reload()
  121. logger.info('cardNo=%s,openId=%s,result=%s,fee=%s,info=%s' % (
  122. cardNo, card.openId, result, fee, self.event_data))
  123. res = "01" if result["balance"] >= fee else "02"
  124. balance = RMB(0) if not card else card.balance
  125. try:
  126. logger.info("card is <{}> fee is <{}> response res is <{}>".format(cardNo, fee, res))
  127. result = self.deviceAdapter.response_card_status(cardNo, balance, res)
  128. except Exception, e: # 启动失败需要把金币还回去
  129. logger.info('resp back error=%s' % e)
  130. return
  131. if fee <= RMB(0):
  132. logger.debug(
  133. 'query the balance of card<cardNo={}> in device<devNo={}>'.format(card.cardNo, self.device.devNo))
  134. return
  135. # 设备回复扣款成功,服务器就需要正式扣掉钱
  136. if result['status'] == '01' and res == '01':
  137. virtual_card = card.bound_virtual_card
  138. if virtual_card is not None:
  139. group = Group.get_group(self.device['groupId'])
  140. VCardConsumeRecord(
  141. orderNo=VCardConsumeRecord.make_no(self.device.logicalCode),
  142. openId=card.openId,
  143. cardId=str(virtual_card.id),
  144. dealerId=card.dealerId,
  145. devNo=self.device.devNo,
  146. devTypeCode = self.device.devTypeCode,
  147. devTypeName = self.device.devTypeName,
  148. logicalCode=self.device['logicalCode'],
  149. groupId=group['groupId'],
  150. address=group['address'],
  151. groupNumber=self.device['groupNumber'],
  152. groupName=group['groupName'],
  153. ).save()
  154. else:
  155. self.consume_money_for_card(card, fee)
  156. # 记录卡消费记录以及消费记录
  157. orderNo, cardOrderNo = self.record_consume_for_card(card, fee)
  158. # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
  159. ServiceProgress.register_card_service(
  160. self.device, -1, card,
  161. {
  162. 'orderNo': orderNo,
  163. 'money': self.event_data['fee'],
  164. 'coin': self.event_data['fee'],
  165. 'needTime': 0,
  166. 'cardOrderNo': cardOrderNo
  167. }
  168. )
  169. # 通知微信,已经扣费
  170. self.notify_balance_has_consume_for_card(card, fee)
  171. elif self.event_data['cmdCode'] == '11' and self.event_data['status'] == '01': # 开始启动某个端口
  172. # 按下端口,开始使用。IC卡和ID卡都会上报这条信息。IC卡只记录消费记录信息,ID卡主要是上报了具体的某一个端口.ID卡和劲能的类似,主要是表示开始某一个端口以及回收余额
  173. cardType = self.event_data['cardType']
  174. card = self.update_card_dealer_and_type(self.event_data['cardNo'], cardType)
  175. # 这个地方将计费方式更新到 portDict 刷卡退费的时候会将刷卡的退费金额上报过来 结束事件需要这个字段 主要的是要更新consumeDict的字段
  176. # 0 按时间收费
  177. # 1 按度计费
  178. consumeModule = self.device.get("otherConf", dict()).get("consumeModule", 0)
  179. if consumeModule == 0:
  180. self.event_data["billingType"] = "time"
  181. else:
  182. self.event_data["billingType"] = "elec"
  183. if cardType == 'ID':
  184. consumeDict = {'chargeIndex': self.event_data['port']}
  185. queryDict = {'device_imei': self.device.devNo,
  186. 'port': -1, 'isFinished': False,
  187. 'cardId': str(card.id), 'start_time': {'$gte': int(time.time()) - 3600}}
  188. progressDict = {'port': self.event_data['port']}
  189. ServiceProgress.update_progress_and_consume_rcd(ownerId=self.device.ownerId,
  190. queryDict=queryDict, consumeDict=consumeDict,
  191. updateConsume=True, progressDict=progressDict)
  192. # 找出对应的卡的ID记录到端口内存数据
  193. queryDict.update(progressDict)
  194. rcds = ServiceProgress.get_collection().find(queryDict, {'consumeOrder': 1},
  195. sort=[('start_time', -1)])
  196. allCoins = sum_rmb([rcd['consumeOrder']['coin'] for rcd in rcds])
  197. self.event_data.update({'cardId': str(card.id)})
  198. self.event_data.update({'openId': card.openId})
  199. self.event_data.update({'coins': str(allCoins)})
  200. self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  201. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  202. Device.update_port_control_cache(self.device.devNo, self.event_data) # 记录该端口累计需要的时间和钱,cardId
  203. else: # IC卡,需要记录消费记录
  204. if card is not None:
  205. fee = RMB(self.event_data['fee'])
  206. card.balance = RMB(self.event_data['balance'])
  207. try:
  208. card.save()
  209. except Exception, e:
  210. logger.exception(e)
  211. orderNo, cardOrderNo = self.record_consume_for_card(card, fee)
  212. ServiceProgress.register_card_service(self.device, self.event_data['port'], card,
  213. {'orderNo': orderNo, 'money': self.event_data['fee'],
  214. 'coin': self.event_data['fee'], 'cardOrderNo': cardOrderNo})
  215. # 通知微信,已经扣费
  216. self.notify_balance_has_consume_for_card(card, fee)
  217. self.event_data.update({'cardId': str(card.id)})
  218. self.event_data.update({'openId': card.openId})
  219. self.event_data.update({'coins': self.event_data['fee']})
  220. self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  221. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  222. Device.update_port_control_cache(self.device.devNo, self.event_data) # 记录该端口累计需要的时间和钱,cardId
  223. # YuhuanNorther.send_dev_status(self.device, self.event_data['port'], 1)
  224. elif self.event_data['cmdCode'] == '17': # 余额回收
  225. card = self.update_card_dealer_and_type(self.event_data['cardNo'], 'IC') # type: Card
  226. if not card:
  227. logger.warning('Card<dealerId={},cardNo={},type=IC> is not registered.'.format(
  228. str(self.dealer.id), self.event_data['cardNo']))
  229. return
  230. self.refund_money_for_card(RMB(self.event_data['backMoney']), card.id)
  231. elif self.event_data['cmdCode'] == '12':
  232. cardNo = self.event_data['cardNo']
  233. preBalance = RMB(self.event_data['balance'])
  234. card = self.update_card_dealer_and_type(cardNo, 'IC', balance=preBalance) # type: Card
  235. if not card:
  236. return
  237. if card.frozen:
  238. logger.debug('{} has been frozen.'.format(repr(card)))
  239. return
  240. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder
  241. if not card_recharge_order:
  242. logger.debug('{} has no recharge order.'.format(repr(card)))
  243. return
  244. self.recharge_ic_card(card=card,
  245. preBalance=preBalance,
  246. rechargeType='overwrite',
  247. order=card_recharge_order)
  248. elif self.event_data['cmdCode'] == '05':
  249. # 新版本的结束事件,比就版本多刷卡ID卡的在线退费
  250. devNo = self.device.devNo
  251. port = str(self.event_data['port'])
  252. try:
  253. # 这个lineInfo 就是缓存全部的信息
  254. lineInfo = Device.clear_port_control_cache(devNo, port)
  255. if not lineInfo:
  256. logger.debug('get null control cache from {}'.format(repr(self.device)))
  257. return
  258. logger.debug('port<{}> cache is: {}'.format(port, str(lineInfo)))
  259. billingType = lineInfo.get("billingType", "time")
  260. if billingType == "elec":
  261. return self.do_elec_finish(devNo, port, lineInfo, self.event_data)
  262. else:
  263. return self.do_time_finish(devNo, port, lineInfo, self.event_data)
  264. finally:
  265. notify_event_to_north(self.dealer, self.device, level=Const.EVENT_NORMAL,
  266. desc=self.event_data.get('reason'))
  267. send_event_to_zhejiang(self.dealer, self.device, self.event_data)
  268. if self.event_data['reasonCode'] == '04': # 功率过载导致的断电,一条告警,一条恢复告警
  269. pass
  270. elif self.event_data['cmdCode'] == '48':
  271. # 没有报端口
  272. leftTime = self.event_data.get('leftTime', 0)
  273. nowPower = self.event_data.get('nowPower', 0)
  274. nowPowerRatio = self.event_data.get('nowPowerRatio', 0)
  275. ctlDict = Device.get_dev_control_cache(self.device.devNo)
  276. for port, info in ctlDict.items():
  277. if isinstance(info, dict):
  278. doPowerLevel = info.get('doPowerLevel', '')
  279. if doPowerLevel == True or doPowerLevel == '':
  280. continue
  281. realTime = info['needTime'] * nowPowerRatio / 100
  282. if abs(realTime - leftTime) <= 3:
  283. info['doPowerLevel'] = True
  284. info['powerLevelTime'] = leftTime
  285. info['power'] = nowPower
  286. info['port'] = port
  287. Device.update_port_control_cache(self.device.devNo, info)
  288. else:
  289. pass
  290. def do_elec_finish(self, devNo, port, lineInfo, msgDict):
  291. """
  292. 电川的板子 按电量退费
  293. :return:
  294. """
  295. logger.info("[{} do_elec_finish] devNo = {}, port = {}, lineInfo = {}, msgDict = {}, event = {}".format(
  296. self.__class__.__name__, devNo, port, lineInfo, msgDict, self.event_data))
  297. if not self.dealer:
  298. logger.error(
  299. "[{} do_elec_finish] dealer {} is not found!".format(self.__class__.__name__, self.device.ownerId))
  300. return
  301. # 提取事件信息
  302. leftElec = self.event_data.get("leftTime", 0) / 100.0
  303. reasonCode = self.event_data.get("endType")
  304. reasonStr = self.event_data.get("reason")
  305. cardNo = self.event_data.get("cardNo", None)
  306. cardType = self.event_data.get("cardType", None)
  307. price = RMB(lineInfo.get('price', 0))
  308. startTime = lineInfo.get("startTime")
  309. # 投币事件
  310. if not startTime:
  311. return
  312. startTime = to_datetime(startTime)
  313. recvTime = to_datetime(self.recvTime)
  314. deviceDuration, deviceElec = self.__parse_device_finished_data(self.event_data)
  315. try:
  316. consumeDict = {
  317. "reason": reasonStr,
  318. "chargeIndex": port,
  319. "uartData": self.event_data.get('uartData', '')
  320. }
  321. # 计算充电的时间
  322. if deviceDuration and deviceDuration > 0:
  323. usedTime = deviceDuration
  324. else:
  325. if startTime > recvTime:
  326. usedTime = 0
  327. else:
  328. usedTime = int(round(((recvTime - startTime).total_seconds() / 60.0)))
  329. refundProtectionTime = self.device.get_other_conf_item('refundProtectionTime', 3)
  330. consumeDict.update({"duration": usedTime})
  331. # 获取组信息
  332. group = Group.get_group(self.device["groupId"])
  333. coins = VirtualCoin(lineInfo.get("coins"))
  334. # 扫码的结束
  335. if not cardNo:
  336. consumeDict.update({
  337. "reason": reasonStr,
  338. "chargeIndex": port
  339. })
  340. needElec = lineInfo.get("needElec")
  341. refundCoins = VirtualCoin(0)
  342. refundedMoney = RMB(0)
  343. if leftElec == int("FFFF", 16):
  344. refundCoins = VirtualCoin(coins)
  345. refundedMoney = RMB(price)
  346. leftElec = needElec
  347. spendElec = 0
  348. else:
  349. if usedTime < refundProtectionTime:
  350. refundCoins = VirtualCoin(coins)
  351. refundedMoney = RMB(price)
  352. spendElec = 0
  353. else:
  354. if leftElec > needElec:
  355. logger.error('left elec is bigger than need elec. something is wrong')
  356. leftElec = 0
  357. spendElec = needElec - leftElec
  358. refundSwitch = self.device.is_auto_refund
  359. if refundSwitch:
  360. refundCoins = VirtualCoin(coins) * Ratio(leftElec / needElec)
  361. refundedMoney = RMB(price) * Ratio(leftElec / needElec)
  362. logger.debug('left elec = {}, duration = {}, need elec = {}, back coins = {}, refund cash = {}'.format(
  363. leftElec, usedTime, needElec, refundCoins, refundedMoney))
  364. if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']:
  365. # 虚拟卡的结束
  366. consumeRcdId = lineInfo['consumeRcdId']
  367. vCardId = lineInfo.get("vCardId", "")
  368. vCard = UserVirtualCard.objects(id=vCardId).first()
  369. if not vCard:
  370. logger.info('can not find the vCard id = %s' % vCardId)
  371. return
  372. try:
  373. ServiceProgress.update_progress_and_consume_rcd(
  374. self.device.ownerId,
  375. {
  376. 'open_id': lineInfo['openId'],
  377. 'port': int(port),
  378. 'device_imei': self.device.devNo,
  379. 'isFinished': False
  380. },
  381. consumeDict
  382. )
  383. if refundCoins > VirtualCoin(0):
  384. vCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRcdId)
  385. vCard.refund_quota(vCardConsumeRcd, needElec - spendElec, spendElec,
  386. refundCoins.mongo_amount)
  387. finally:
  388. user = MyUser.objects(openId=lineInfo['openId'],
  389. groupId=self.device.groupId).first()
  390. self.notify_user_service_complete(
  391. service_name=u'充电',
  392. openid=user.managerialOpenId if user else '',
  393. port=port,
  394. address=group['address'],
  395. reason=self.event_data['reason'],
  396. finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  397. extra=[
  398. {u'虚拟卡号': vCard.cardNo}
  399. ]
  400. )
  401. elif 'openId' in lineInfo and lineInfo['openId']:
  402. # 扫码使用金币启动
  403. user = MyUser.objects(openId=lineInfo['openId'],
  404. groupId=self.device.groupId).first()
  405. try:
  406. is_cash = False
  407. if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0):
  408. is_cash = True
  409. if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0):
  410. self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash)
  411. ServiceProgress.update_progress_and_consume_rcd(
  412. self.device.ownerId,
  413. {
  414. 'open_id': lineInfo['openId'],
  415. 'port': int(port),
  416. 'device_imei': self.device.devNo,
  417. 'isFinished': False
  418. },
  419. consumeDict)
  420. finally:
  421. extra = []
  422. if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
  423. real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH])
  424. if real_refund > RMB(0):
  425. extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)})
  426. extra.append({u'退款金额': '{}(元)'.format(real_refund)})
  427. else:
  428. extra.append({u'消费金额': '{}(元)'.format(price)})
  429. elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
  430. real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS])
  431. if real_refund > VirtualCoin(0):
  432. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)})
  433. extra.append({u'退款金额': '{}(金币)'.format(real_refund)})
  434. else:
  435. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  436. consumeDict.update({
  437. DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(coins) - real_refund).mongo_amount
  438. })
  439. else:
  440. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  441. consumeDict.update({
  442. DEALER_CONSUMPTION_AGG_KIND.COIN: VirtualCoin(coins).mongo_amount
  443. })
  444. self.notify_user_service_complete(
  445. service_name=u'充电',
  446. openid=user.managerialOpenId if user else '',
  447. port=port,
  448. address=group['address'],
  449. reason=self.event_data['reason'],
  450. finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  451. extra=extra)
  452. else:
  453. logger.error('not net pay rather user virtual card pay. something is wrong.')
  454. else:
  455. backMoney = self.event_data.get("backMoney")
  456. # 刷卡的结束 如果没有开启刷卡退费 则结束上报过来的backMoney = 0
  457. if cardType == "IC":
  458. # IC卡结束 只有刷卡结束的IC卡才能够刷新IC卡余额
  459. card = self.update_card_dealer_and_type(cardNo, "IC")
  460. if reasonCode == "05" and backMoney > 0:
  461. # 原因为05表示刷卡结束充电,会把退费金额报上来. 否则只能通过11指令报上来
  462. self.refund_money_for_card(VirtualCoin(backMoney), card.id)
  463. consumeDict.update({'balance': str(card.balance + VirtualCoin(backMoney))})
  464. else:
  465. consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来
  466. elif cardType == "ID":
  467. # ID卡结束 直接退费就行了
  468. card = self.update_card_dealer_and_type(cardNo, "ID")
  469. if backMoney > 0:
  470. self.refund_money_for_card(RMB(backMoney), str(card.id))
  471. consumeDict.update({
  472. DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: VirtualCoin(backMoney).mongo_amount
  473. })
  474. consumeDict.update({'balance': str(card.balance + VirtualCoin(backMoney))})
  475. else:
  476. logger.error("invalid card type event data is <{}>".format(self.event_data))
  477. ServiceProgress.update_progress_and_consume_rcd(
  478. self.device.ownerId,
  479. {
  480. 'open_id': lineInfo['openId'],
  481. 'port': int(port),
  482. 'device_imei': self.device.devNo,
  483. 'isFinished': False
  484. },
  485. consumeDict
  486. )
  487. extra = [{u'实体卡号': cardNo}]
  488. if backMoney > 0:
  489. extra.append({
  490. u'退款金额': u'{}(金币)'.format(backMoney)
  491. })
  492. self.notify_user_service_complete(
  493. service_name=u'充电',
  494. openid=self.get_managerialOpenId_by_openId(lineInfo['openId']),
  495. port=port,
  496. address=group['address'],
  497. reason=self.event_data['reason'],
  498. finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  499. extra=extra
  500. )
  501. except Exception as e:
  502. logger.exception(e)
  503. def do_time_finish(self, devNo, port, lineInfo, msgDict):
  504. logger.info("[{} do_time_finish] devNo = {}, port = {}, lineInfo = {}, msgDict = {}, event = {}".format(
  505. self.__class__.__name__, devNo, port, lineInfo, msgDict, self.event_data))
  506. try:
  507. if not self.dealer:
  508. logger.error(
  509. "[{} do_time_finish] dealer {} is not found!".format(self.__class__.__name__, self.device.ownerId))
  510. return
  511. price = RMB(lineInfo.get('price', 0))
  512. refundProtectionTime = self.device.get_other_conf_item('refundProtectionTime', 5)
  513. deviceDuration, deviceElec = self.__parse_device_finished_data(self.event_data)
  514. recvTime = to_datetime(self.recvTime)
  515. if lineInfo is not None and 'startTime' in lineInfo:
  516. startTime = to_datetime(lineInfo['startTime'])
  517. if startTime > recvTime:
  518. logger.error('start time is bigger than now time,devNo={}'.format(devNo))
  519. serverDuration = -1
  520. else:
  521. serverDuration = int(round((((recvTime - startTime).total_seconds() + 59) / 60.0)))
  522. else:
  523. logger.info('lineinfo has not startTime,devNo=%s' % devNo)
  524. serverDuration = -1
  525. leftTime = self.event_data['leftTime']
  526. logger.debug('serverDuration = {}; deviceDuration = {}; leftTime = {}; lineInfo = {}'.format(
  527. serverDuration, deviceDuration, leftTime, lineInfo))
  528. if serverDuration < 0 and deviceDuration < 0:
  529. logger.warning('serverDuration and deviceDuration is valid. ignore this event.')
  530. return
  531. usedTime = 0
  532. if leftTime == 65535: # 设备返回65535说明端口没有启动
  533. leftTimeStr = u'端口未使用'
  534. actualNeedTime = 0
  535. else:
  536. usedTime = max(serverDuration, deviceDuration)
  537. leftTimeStr = leftTime
  538. actualNeedTime = usedTime + leftTime
  539. if usedTime < refundProtectionTime:
  540. # 通过使用的时间来判断是否可以进行保险的退款
  541. rechargeIds = list()
  542. payInfo = lineInfo.get('payInfo', list())
  543. for item in payInfo:
  544. if 'rechargeRcdId' not in item:
  545. continue
  546. rechargeIds.append(item['rechargeRcdId'])
  547. group = self.device.group # type: GroupDict
  548. consumeDict = {
  549. 'reason': self.event_data['reason'],
  550. 'leftTime': leftTimeStr,
  551. 'chargeIndex': port,
  552. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  553. 'duration': usedTime,
  554. 'deviceDuration': deviceDuration,
  555. 'serverDuration': serverDuration,
  556. 'uartData': self.event_data.get('uartData', '')
  557. }
  558. try:
  559. groupObj = Group.objects(id=self.device.groupId).first()
  560. if groupObj.otherConf.get('zhuxing', None) is not None:
  561. spendElec = round((float(random.randint(15, 19)) / 100) * (float(usedTime) / 60), 3)
  562. consumeDict.update({'elec': spendElec})
  563. consumeDict.update({'elecFee': self.deviceAdapter.calc_elec_fee(spendElec)})
  564. else:
  565. if deviceElec != -1:
  566. consumeDict.update({'elec': deviceElec})
  567. if deviceElec == 0 and usedTime > 0:
  568. consumeDict.update(
  569. {'elec': round((float(random.randint(15, 19)) / 100) * (float(usedTime) / 60), 3)})
  570. else:
  571. consumeDict.update({'elec': 0.0})
  572. consumeDict.update({'elecFee': RMB(0.0).mongo_amount})
  573. except Exception as e:
  574. logger.error("device <{}> elec add error! <{}>".format(self.device.devNo, e))
  575. # 涉及到卡的退费 不要以缓存为准 以设备上报的为准
  576. cardNo = self.event_data.get("cardNo", None)
  577. if cardNo:
  578. # 如果是刷卡的,直接更新消费记录,发通知消息,支持ID卡的退费。
  579. # IC卡的退费, 如果结束原因是刷卡退费(05), 则会把退费信息返回;
  580. # 否则不会把退费信息传过来,会通过11号命令返回
  581. cardType = self.event_data.get("cardType")
  582. if cardType == 'ID':
  583. card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="ID")
  584. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  585. if self.event_data.has_key('backMoney') and self.event_data['backMoney'] > 0:
  586. self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id)
  587. # 通知微信,已经退费
  588. self.notify_user(card.managerialOpenId, 'refund_coins', **{
  589. 'title': u'退币完成!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
  590. 'backCount': u'金币:%s' % VirtualCoin(self.event_data['backMoney']),
  591. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S')
  592. })
  593. elif cardType == "IC":
  594. card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="IC")
  595. if not card:
  596. logger.warning('Card<dealerId={},cardNo={},type=IC> is not registered.'.format(
  597. str(self.dealer.id), cardNo))
  598. return
  599. # IC 并且结束code是05 表示卡贴上去了
  600. if self.event_data['endType'] == '05': # 刷卡退费结束的时候,才能够刷新IC卡的余额
  601. self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id)
  602. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  603. else:
  604. consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来
  605. else:
  606. logger.error("invalid card type event data is <{}>".format(self.event_data))
  607. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  608. {'open_id': lineInfo['openId'], 'port': int(port),
  609. 'device_imei': self.device.devNo,
  610. 'isFinished': False}, consumeDict)
  611. extra = [{
  612. u'实体卡号': lineInfo['cardNo']
  613. }]
  614. if VirtualCoin(self.event_data['backMoney']) > VirtualCoin(0):
  615. extra.append({
  616. u'退费金额': u'{}(金币)'.format(self.event_data['backMoney'])
  617. })
  618. self.notify_user_service_complete(
  619. service_name=u'充电',
  620. openid=card.managerialOpenId if card else '',
  621. port=port,
  622. address=group['address'],
  623. reason=self.event_data['reason'],
  624. finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  625. extra=extra)
  626. else:
  627. if 'coins' not in lineInfo:
  628. logger.warning('has no coins fields in lineInfo. may be coins start.')
  629. return
  630. coins = VirtualCoin(lineInfo['coins'])
  631. refundCoins = VirtualCoin(0)
  632. refundedMoney = RMB(0)
  633. if leftTime == 65535 or (usedTime < refundProtectionTime):
  634. refundCoins = coins
  635. refundedMoney = RMB(price)
  636. elif self.device.is_auto_refund:
  637. refundCoins = coins * (float(leftTime) / float(actualNeedTime))
  638. refundedMoney = RMB(price * (float(leftTime) / float(actualNeedTime)))
  639. if refundCoins > coins:
  640. refundCoins = coins
  641. if refundedMoney > RMB(price):
  642. refundedMoney = RMB(price)
  643. logger.debug('left time = {}, duration = {}, need time = {}, back coins = {}, refund money = {}'.format(
  644. leftTime, usedTime, actualNeedTime, refundCoins, refundedMoney))
  645. if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']:
  646. vCardId = lineInfo['vCardId']
  647. vCard = UserVirtualCard.objects(id=vCardId).first() # type: UserVirtualCard
  648. if not vCard:
  649. logger.info('can not find the vCard id = %s' % vCardId)
  650. return
  651. try:
  652. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  653. {'open_id': lineInfo['openId'],
  654. 'port': int(port),
  655. 'device_imei': self.device.devNo,
  656. 'isFinished': False}, consumeDict)
  657. if refundCoins > VirtualCoin(0):
  658. vCardConsumeRcd = VCardConsumeRecord.objects.get(id=lineInfo['consumeRcdId'])
  659. vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, refundCoins.mongo_amount)
  660. finally:
  661. user = MyUser.objects(openId=lineInfo['openId'],
  662. groupId=self.device.groupId).first()
  663. self.notify_user_service_complete(
  664. service_name=u'充电',
  665. openid=user.managerialOpenId if user else '',
  666. port=port,
  667. address=group['address'],
  668. reason=self.event_data['reason'],
  669. finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  670. extra=[
  671. {u'虚拟卡号': vCard.cardNo}
  672. ]
  673. )
  674. elif 'openId' in lineInfo and lineInfo['openId']:
  675. user = MyUser.objects(openId=lineInfo['openId'],
  676. groupId=self.device.groupId).first()
  677. try:
  678. is_cash = False
  679. if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0):
  680. is_cash = True
  681. if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0):
  682. self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash)
  683. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  684. {'open_id': lineInfo['openId'],
  685. 'port': int(port),
  686. 'device_imei': self.device.devNo,
  687. 'isFinished': False}, consumeDict)
  688. finally:
  689. extra = []
  690. if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
  691. real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH])
  692. if real_refund > RMB(0):
  693. extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)})
  694. extra.append({u'退款金额': '{}(元)'.format(real_refund)})
  695. else:
  696. extra.append({u'消费金额': '{}(元)'.format(price)})
  697. elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
  698. real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS])
  699. if real_refund > VirtualCoin(0):
  700. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)})
  701. extra.append({u'退款金额': '{}(金币)'.format(real_refund)})
  702. else:
  703. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  704. else:
  705. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  706. self.notify_user_service_complete(
  707. service_name=u'充电',
  708. openid=user.managerialOpenId if user else '',
  709. port=port,
  710. address=group['address'],
  711. reason=self.event_data['reason'],
  712. finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  713. extra=extra)
  714. else:
  715. logger.error('not net pay rather user virtual card pay. something is wrong.')
  716. except Exception as e:
  717. logger.exception(e)
  718. class DIANCHUANFaultEvent(FaultEvent):
  719. def do(self, **args):
  720. detail = {"errorCode": self.event_data["faultCode"]}
  721. self.event_data["detail"] = detail
  722. super(DIANCHUANFaultEvent, self).do()
  723. class DIANCHUANInductorEvent(FaultEvent):
  724. def do(self, **args):
  725. # 处理数据
  726. temperatureLast = self.event_data.get('temperatureLast', None)
  727. smokeWarning = self.event_data.get('smokeWarning', False)
  728. try:
  729. faultName = "告警"
  730. faultCode = ""
  731. desc = ""
  732. if temperatureLast:
  733. logger.info('Warning!!! Temperature exceeds upper limit')
  734. temperatureMax = self.device.get('otherconf', {}).get('temperatureMax', 60)
  735. desc = u'当前主机温度%s度超过了门限值:%s度' % (temperatureLast, temperatureMax)
  736. faultName = u"主机温度告警"
  737. faultCode = FAULT_CODE.OVER_TEMPERATURE
  738. if smokeWarning:
  739. logger.info('Warning!!! Smoke sensor alarm')
  740. desc = u'当前主机出现冒烟,请第一时间确定是否有起火。此告警十万火急,请迅速联系物业、消防相关部门!'
  741. faultName = u"主机烟雾告警"
  742. faultCode = FAULT_CODE.SMOKE
  743. except Exception, e:
  744. logger.error('some error=%s' % e)
  745. return
  746. detail = {"errorCode": self.event_data["faultCode"]}
  747. self.event_data.update({
  748. "faultName": faultName,
  749. "faultCode": faultCode,
  750. "level": FAULT_LEVEL.CRITICAL,
  751. "desc": desc,
  752. "detail": detail
  753. })
  754. super(DIANCHUANInductorEvent, self).do(**args)
  755. class DIANCHUANAlertEvent(FaultEvent):
  756. def __Analyze_alert_data(self, data):
  757. alertInfo = {'cmdCode': data['cmd'], 'logicalCode': self.device['logicalCode']}
  758. address = Group.get_group(self.device['groupId'])['address']
  759. # 这里判断数据格式
  760. if 'status' not in data:
  761. logger.error('Data arrays have no keywords status')
  762. return
  763. # 这里做漏电告警处理
  764. if '5' in data['status']:
  765. electricityNum = str(int(data['values'][0:4], 16)) + 'mA'
  766. alertInfo['electricity'] = {'electricityNum': electricityNum,
  767. 'address': address,
  768. 'reasonCode': '12',
  769. 'reason': u'在{}编号为{}发生漏电,漏电量为{}'
  770. .format(address, self.device['logicalCode'], electricityNum)}
  771. # 这里做高温告警处理
  772. if '6' in data['status']:
  773. temperatureAccess = [index for index, acces in enumerate(data['status'], 1) if acces == '6']
  774. temperatureAlertList = []
  775. for i in temperatureAccess:
  776. temperatureValue = str(int(data['values'][(i - 1) * 4:(i - 1) * 4 + 4], 16))
  777. temperatureAlertList.append(
  778. {'temperatureValue': temperatureValue,
  779. 'address': address,
  780. 'reasonCode': '11',
  781. 'reason': u'在{}编号为{}的设备有高温预警,当前温度为{}摄氏度'
  782. .format(address, self.device['logicalCode'], temperatureValue)})
  783. alertInfo['temperature'] = temperatureAlertList
  784. return alertInfo
  785. def do(self, **args):
  786. # 判断不存在的设备网上报
  787. if not self.device.ownerId:
  788. logger.error('This device cant find a dealer')
  789. return
  790. # 是否存在温感和电感
  791. temperaturePart = Part.objects(logicalCode=self.device['logicalCode'], partType='3001')
  792. electricityPart = Part.objects(logicalCode=self.device['logicalCode'], partType='3002')
  793. if not temperaturePart.count() or not electricityPart.count():
  794. logger.error(
  795. 'There are no transformers in the locigalcode {} equipment'.format(self.device['logicalCode']))
  796. return
  797. # 处理数据
  798. eventInfo = self.__Analyze_alert_data(self.event_data['data'])
  799. try:
  800. # 先处理高温情况
  801. if 'temperature' in eventInfo:
  802. for InfoDetail in eventInfo['temperature']:
  803. send_event_to_zhejiang(self.dealer, self.device, InfoDetail, partId=temperaturePart[0].id)
  804. # 提示用户
  805. group = Group.get_group(self.device['groupId'])
  806. self.notify_dealer('device_fault', **{
  807. 'title': u'注意!注意!您的设备发生故障',
  808. 'device': u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']),
  809. 'location': u'组名称:%s, 地址:%s' % (group['groupName'], group['address']),
  810. 'fault': InfoDetail['reason'],
  811. 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  812. })
  813. # 上报高温至消防
  814. # if self.device["ownerId"] in ("5b4ed32e8732d67bd0626528", "5b6c29388732d669f3ae6f94"):
  815. group = Group.get_group(self.device['groupId'])
  816. districtInfo = District.get_district(group["districtId"])
  817. self.device.update({"districtInfo": districtInfo, "groupAddr": group["address"]})
  818. LiangXiXiaoFang.send_to_xf_fault(self.device, "01", u"设备温度过高")
  819. # 处理漏电情况
  820. elif 'electricity' in eventInfo:
  821. # 获取漏电告警插件
  822. send_event_to_zhejiang(self.dealer, self.device, eventInfo['electricity'],
  823. partId=electricityPart[0].id)
  824. # 提示用户
  825. group = Group.get_group(self.device['groupId'])
  826. self.notify_dealer('device_fault', **{
  827. 'title': u'注意!注意!您的设备发生故障',
  828. 'device': u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']),
  829. 'location': u'组名称:%s, 地址:%s' % (group['groupName'], group['address']),
  830. 'fault': eventInfo['electricity']['reason'],
  831. 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  832. })
  833. # 上报漏电至消防
  834. # if self.device["ownerId"] in ("5b4ed32e8732d67bd0626528", "5b6c29388732d669f3ae6f94"):
  835. group = Group.get_group(self.device['groupId'])
  836. districtInfo = District.get_district(group["districtId"])
  837. self.device.update({"districtInfo": districtInfo, "groupAddr": group["address"]})
  838. LiangXiXiaoFang.send_to_xf_fault(self.device, "04", u"设备发生漏电")
  839. except:
  840. logger.error('Array {} nonspecification'.format(eventInfo))
  841. return
  842. self.record(detail=eventInfo)
  843. class DIANCHUANReport(WorkEvent):
  844. def do(self, **args):
  845. if 'type' not in self.event_data:
  846. logger.error('Array {} is not format,lose a key named "type"'.format(self.event_data))
  847. if self.event_data.get('type') == 'report':
  848. devReportDict = {'logicalCode': 'logicalCode', 'time': self.event_data['time_stamp'], 'portInfo': {}}
  849. temperature = ''
  850. voltage = 220
  851. try:
  852. # 拿到个数判断是不是第一次
  853. reportNum = PortReport.get_collection().find({
  854. 'logicalCode': self.device['logicalCode']
  855. }).sort('time', -1).count()
  856. if reportNum:
  857. # 获取上一次存储的信息
  858. reportLast = PortReport.get_collection().find({
  859. 'logicalCode': self.device['logicalCode']
  860. }).sort('time', -1)[0]
  861. for ii in range(10):
  862. power = self.__saveDate(1, msgDict=self.event_data, ii=ii)
  863. if power:
  864. electricity = float(power) / voltage / 10
  865. else:
  866. electricity = reportLast['portInfo'][str(ii + 1)]['electricity']
  867. temperatureR = self.__saveDate(2, msgDict=self.event_data, ii=ii, electricity=electricity,
  868. devReportDict=devReportDict)
  869. if temperatureR:
  870. temperature = temperatureR
  871. devReportDict.update({'temperature': temperature})
  872. # 查看现在的跟以前差距多少
  873. timeInterval = devReportDict['time'] - reportLast['time']
  874. if timeInterval > 2:
  875. PortReportNewList = [
  876. {"logicalCode": self.device['logicalCode'], "temperature": reportLast['temperature'],
  877. 'portInfo': reportLast['portInfo'],
  878. 'time': reportLast['time'] + (v + 1) * 2}
  879. for v in range(int(timeInterval / 2) - 1)]
  880. PortReport.get_collection().insert_many(PortReportNewList)
  881. # 首存的情况
  882. else:
  883. for ii in range(10):
  884. power = self.__saveDate(1, msgDict=self.event_data, ii=ii)
  885. electricity = float(power) / voltage / 10
  886. temperatureR = self.__saveDate(2, msgDict=self.event_data, ii=ii, electricity=electricity,
  887. devReportDict=devReportDict)
  888. if temperatureR:
  889. temperature = temperatureR
  890. devReportDict.update({'temperature': temperature})
  891. except Exception, e:
  892. logger.error('solve dev=%s device report has an error e=%s' % (self.device.devNo, e))
  893. finally:
  894. newInfo = PortReport(
  895. logicalCode=self.device['logicalCode'],
  896. temperature=devReportDict['temperature'],
  897. time=devReportDict['time'],
  898. portInfo=devReportDict['portInfo']
  899. )
  900. newInfo.save()
  901. def __saveDate(self, data, msgDict, ii, electricity=None, devReportDict=None):
  902. # 存储数据库
  903. if data == 1:
  904. powerData = msgDict['data']['power_data'][0 + 4 * ii:4 + 4 * ii]
  905. power = int(powerData, 16)
  906. return power
  907. if data == 2:
  908. temperature = ''
  909. status = 'idle' if electricity == 0 else 'busy'
  910. devReportDict['portInfo'].update(
  911. {str(ii + 1): {'electricity': round(electricity, 3), 'status': status}})
  912. if ii < 4 and msgDict['data']['temp_data'][0 + 4 * ii:4 + 4 * ii] != '0000':
  913. temperatureNum = msgDict['data']['temp_data'][0 + 4 * ii:4 + 4 * ii]
  914. temperature = int(temperatureNum, 16)
  915. return temperature