12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- """
- 和动V3 主板:
- 特性:
- 1 扫码使用27指令的充满自停 (下发时间 则按时间严格执行, 无时间则最大充电时间充满自停) 无法做到续充
- 2 刷卡: 只支持充满自停在线卡(该卡片在一台设备上只能刷一次)
- """
- import datetime
- import logging
- import time
- from arrow import Arrow
- from django.conf import settings
- from typing import Optional, Dict, TYPE_CHECKING
- from apps.web.agent.models import Agent
- from apps.web.constant import DeviceCmdCode, Const
- from apps.web.core.device_define.hedongv3 import Cmd, CMD_CODE
- from apps.web.core.helpers import ActionDeviceBuilder
- from apps.web.core.adapter.base import SmartBox, fill_2_hexByte
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.dealer.models import Dealer
- from apps.web.device.models import Device, Group, DeviceType
- from apps.web.eventer.base import AckEvent
- from apps.web.user.models import ConsumeRecord, Card
- from taskmanager.mediator import task_caller
- if TYPE_CHECKING:
- from apps.web.api.models import APIStartDeviceRecord
- logger = logging.getLogger(__name__)
- class ChargingHDBox(SmartBox):
- """
- 和动V3协议
- """
- def __init__(self, device):
- super(ChargingHDBox, self).__init__(device)
- def isHaveStopEvent(self):
- return True
- def translate_funcode(self, funCode):
- funCodeDict = {
- '01': u'获取端口数量',
- '02': u'获取端口数据',
- '14': u'移动支付',
- '07': u'获取刷卡投币统计数据',
- '15': u'获取设备端口详情',
- '0F': u'获取端口状态',
- '0C': u'端口锁操作',
- '0D': u'端口开关',
- '1E': u'获取设备设置',
- '18': u'设置设备参数',
- '10': u'回复卡余额',
- }
- return funCodeDict.get(funCode, '')
- def translate_event_cmdcode(self, cmdCode):
- cmdDict = {
- '06': u'充电结束',
- '16': u'充电结束',
- '0A': u'故障',
- '10': u'刷卡上报',
- '20': u'启动设备',
- }
- return cmdDict.get(cmdCode, '')
- def test(self, coins,port=1):
- hexElec = fill_2_hexByte(hex(0), 4)
- hexPort = fill_2_hexByte(hex(port), 2)
- hexCoins = fill_2_hexByte(hex(1))
- hexTime = fill_2_hexByte(hex(60))
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], "funCode": '14',
- 'data': hexPort + hexCoins + hexTime + hexElec})
- return devInfo
- def stop(self, port = None):
- infoDict = self.stop_charging_port(port)
- infoDict['remainder_time'] = infoDict['leftTime']
- return infoDict
- def start_from_api(self, record):
- # type: (APIStartDeviceRecord)->Optional[Dict]
- if 'chargeIndex' not in record.attachParas:
- from apps.web.api.exceptions import ApiParameterError
- raise ApiParameterError(u'请传入充电桩端口号chargeIndex参数')
- return super(ChargingHDBox, self).start_from_api(record)
- def analyze_event_data(self, data):
- cmdCode = data[4:6]
- #: 提交充电结束状态 (06)
- #: 老版本
- if cmdCode == CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06:
- port = int(data[8:10], 16)
- leftTime = int(data[10:14], 16)
- reasonCode = data[14:16]
- desc_map = {
- "00": u'购买的充电时间或电量用完了。',
- "01": u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
- "02": u'恭喜您!电池已经充满电!',
- "0B": u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
- }
- return {
- 'status': Const.DEV_WORK_STATUS_IDLE,
- 'cmdCode': cmdCode,
- 'port': port,
- 'leftTime': leftTime,
- 'reason': desc_map[reasonCode],
- 'reasonCode': reasonCode
- }
- #: (高版本的) 提交充电结束状态 (16)
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16:
- port = int(data[8:10], 16)
- leftTime = int(data[10:14], 16)
- elec = int(data[14:18], 16) / 100.0
- reasonCode = data[18:20]
- # 如果设备类型有自定义结束推送通知就走自定义
- devType = DeviceType.objects(id=self.device['devType']['id']).first()
- finishedReasonDict = devType.finishedReasonDict
- if finishedReasonDict != {}:
- desc_map = finishedReasonDict
- else:
- desc_map = {
- '00': u'购买的充电时间或电量用完了。',
- '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
- '02': u'恭喜您!电池已经充满电!',
- '03': u'警告!您的电池超功率,已经停止充电,为了公共安全,不建议您在该充电桩充电!提醒您,为了安全大功率的电池不要放入楼道、室内等位置充电哦',
- '04': u'远程断电。',
- '0B': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
- }
- desc = desc_map.get(reasonCode, u'电池没有充满!原因未知。')
- return {
- 'status': Const.DEV_WORK_STATUS_IDLE,
- 'cmdCode': cmdCode,
- 'port': port,
- 'leftTime': leftTime,
- 'elec': elec,
- 'reason': desc,
- 'reasonCode': reasonCode
- }
- #: 上传设备故障
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A:
- port = int(data[8:10], 16)
- errCode = int(data[10:14], 16)
- if errCode == 1:
- statusInfo = '端口{}:继电器粘连'.format(port)
- else:
- statusInfo = '设备故障'
- return {
- 'status': Const.DEV_WORK_STATUS_FAULT,
- 'statusInfo': statusInfo,
- 'cmdCode': cmdCode,
- 'port': port,
- 'FaultCode': errCode
- }
- # 用户刷卡上报的信息
- #: 在线卡上传卡号,预扣费
- #: 示例:
- #: CARD_ID CARD_CST CARD_OPE
- #: 0x00000000 0x00 0x00
- #: 参数
- #: CARD_ID : IC 卡卡号
- #: CARD_SURP: 卡片需要改变的金额信息(以角为单位)
- #: CARD_OPE: 0x00 是扣费(减少),0x01 是充值(增加)。
- #: 回复
- #: RES: 0x00,表示扣费成功,0x01 表示余额不足,0x02 表示非法卡。
- #: CARD_SURP: 表示卡余额(以角为单位)。
- elif cmdCode == CMD_CODE.SWIPE_CARD_10:
- group = Group.get_group(self._device['groupId'])
- dealer = Dealer.get_dealer(group['ownerId'])
- agent = Agent.objects(id = dealer['agentId']).first()
- device = Device.objects(devNo=self._device['devNo']).first()
- devType = DeviceType.objects(id=device['devType']['id']).first()
- cardNo = str(int(data[8:16], 16))
- # 兼容以前的老代码, 先走以前的老代码, 如果有新代码再走新的.
- if agent is not None and 'cardNoReverse' in agent.features:
- cardData = data[14:16] + data[12:14] + data[10:12] + data[8:10]
- cardNo = str(int(cardData, 16))
- if 'cardNoReverse' in devType.features:
- if devType.features['cardNoReverse'] is True:
- cardData = data[14:16] + data[12:14] + data[10:12] + data[8:10]
- cardNo = str(int(cardData, 16))
- else:
- cardNo = str(int(data[8:16], 16))
- else:
- pass
- #: 卡里的余额,以角为单位
- preFee = int(data[16:18], 16) / 10.0
- #: 操作符 00(增加) | 01(减少)
- oper = data[18:20]
- return {'cardNo': cardNo, 'preFee': preFee, 'cmdCode': cmdCode, 'oper': oper, "sourceData": data}
- #: 上报投币打开的信息
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20: # 启动设备
- port = int(data[8:10], 16)
- needTime = int(data[10:14], 16)
- elec = int(data[14:18], 16) / 100.0
- consumeTypeTemp = data[18:20]
- if consumeTypeTemp == '00':
- consumeType = 'coin'
- elif consumeTypeTemp == '01':
- consumeType = 'card'
- elif consumeTypeTemp == '03':
- consumeType = 'server'
- else:
- consumeType = 'other'
- money = int(data[20:22], 16) / 10.0
- return {
- 'cmdCode': cmdCode,
- 'port': port,
- 'needTime': needTime,
- 'elec': elec,
- 'consumeType': consumeType,
- 'coins': money
- }
- # 4个故障的告警
- elif cmdCode == CMD_CODE.DEVICE_FAULT_FIRE:
- return {"cmdCode": cmdCode, "fault": u"火灾报警"}
- elif cmdCode == CMD_CODE.DEVICE_FAULT_SMOKE:
- return {"cmdCode": cmdCode, "fault": "烟雾报警"}
- elif cmdCode == CMD_CODE.DEVICE_FAULT_TEMPERATURE:
- return {"cmdCode": cmdCode, "fault": "温度超限告警"}
- elif cmdCode == CMD_CODE.DEVICE_FAULT_POWER:
- return {"cmdCode": cmdCode, "fault": "功率超线告警"}
- elif cmdCode == CMD_CODE.DEVICE_FAULT_ALTER:
- fire = int(data[8:10],16)
- smoke = int(data[10:12],16)
- overload = int(data[12:14],16)
- overheat = int(data[14:16],16)
- result = {"cmdCode": cmdCode}
- fault = []
- if fire:
- fault.append("火灾报警")
- if smoke:
- fault.append("烟雾报警")
- if overload:
- fault.append("温度超限告警")
- if overheat:
- fault.append("功率超线告警")
- if fault:
- fault = '--'.join(fault)
- result.update({"fault": fault})
- return result
- # 2个状态量上报
- elif cmdCode == CMD_CODE.DEVICE_FAULT_POWER:
- maxPower = int(data[8:12],16)
- return {"cmdCode": cmdCode, "maxPower": maxPower}
- elif cmdCode == CMD_CODE.DEVICE_FAULT_TEMPERATURE:
- maxTemperature = int(data[8:10],16)
- return {"cmdCode": cmdCode, "maxTemperature": maxTemperature}
- elif cmdCode == CMD_CODE.DEVICE_ELEC:
- elec = int(data[8:12], 16)
- return {"cmdCode": cmdCode, "elec": elec}
- elif cmdCode == CMD_CODE.DEVICE_TEMPERATURE:
- temperature = int(data[10:12], 16)
- if data[8:10] == "00":
- temperature = temperature * -1
- return {"cmdCode": cmdCode, "temperature": temperature}
- elif cmdCode == CMD_CODE.DEVICE_CARD_CHARGE_2D:
- _result = data[6: 8]
- _port = str(int(data[8: 10], 16))
- _time = int(data[10: 14], 16)
- _elec = int(data[14: 18], 16) / 100.0
- _type = data[18: 20]
- _coins = int(data[20: 22], 16)
- _cardNo = str(int(data[22: 30], 16))
- _card_cst = int(data[30: 34], 16) / 10.0
- _operation = data[34: 36]
- _card_type = data[36: 38]
- _session_id = data[38: 46]
- return {
- "portStr": _port,
- "time": _time,
- "elec": _elec,
- "chargeType": _type,
- "coins": _coins,
- "cardNo": _cardNo,
- "cardCst": _card_cst,
- "operation": _operation,
- "cardType": _card_type,
- "sessionId": _session_id,
- "cmdCode": cmdCode,
- "result": _result,
- "sourceData": data
- }
- elif cmdCode == CMD_CODE.DEVICE_REAL_TIME_REPORT_21:
- _result = data[6: 8]
- port_num = int(data[8:10],16)
- port_info_urat_info = data[10:170]
- port_status_desc = {
- "01": "端口空闲",
- "02": "端口正在使用",
- "03": "端口禁用",
- "04": "端口故障",
- }
- port_info = {}
- for index in xrange(0, 160, 16):
- item = port_info_urat_info[index: index + 16]
- one_port = {}
- one_port["port"] = int(item[:2], 16)
- one_port["portStatus"] = item[2:4]
- one_port["portStatusDesc"] = port_status_desc.get(item[2:4])
- one_port["leftTime"] = int(item[4:8], 16)
- one_port["power"] = int(item[8:12], 16)
- one_port["elec"] = int(item[8:12], 16) * 0.01
- port_info[str(one_port["port"])] = one_port
- return {"cmdCode": cmdCode, "result": _result, "sourceData": data, "portNum": port_num,
- "portInfo": port_info}
- elif cmdCode == CMD_CODE.DEVICE_FINISHED_REPORT_2C:
- result = data[6: 8]
- port = int(data[8:10], 16)
- leftTime = int(data[10:14], 16)
- leftElec = round(int(data[14:18], 16) * 0.01, 2)
- cardNoHex = data[18:26]
- cardCst = round(int(data[26:30], 16) * 0.1, 2)
- cardOpe = data[30:32]
- cardType = data[32:34]
- reason = data[34:36]
- sessionId = data[36:44]
- devType = DeviceType.objects(id=self.device['devType']['id']).first()
- finishedReasonDict = devType.finishedReasonDict
- if finishedReasonDict != {}:
- desc_map = finishedReasonDict
- else:
- desc_map = {
- '00': u'购买的充电时间或电量用完了。',
- '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
- '02': u'恭喜您!电池已经充满电!',
- '03': u'警告!您的电池超功率,已经停止充电,为了公共安全,不建议您在该充电桩充电!提醒您,为了安全大功率的电池不要放入楼道、室内等位置充电哦',
- '04': u'远程断电。',
- '0B': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
- }
- reasonDesc = desc_map.get(reason, u'电池没有充满!原因未知。')
- return {
- 'sourceData': data,
- 'result': result,
- 'port': port,
- 'leftTime': leftTime,
- 'leftElec': leftElec,
- 'cardNoHex': cardNoHex,
- 'cardCst': cardCst,
- 'cardOpe': cardOpe,
- 'cardType': cardType,
- 'reason': reason,
- 'sessionId': sessionId,
- 'cmdCode': CMD_CODE.DEVICE_FINISHED_REPORT_2C,
- 'reasonDesc': reasonDesc
- }
- else:
- logger.info("receive data <{}>, cmd is invalid".format(data))
- def get_dev_consume_count(self):
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], "funCode": '07', 'data': '00'})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
- cardFee = int(data[2:6], 16) / 10.0 # 以角为单位
- coinFee = int(data[6:10], 16) # 以元为单位
- return {'cardFee': cardFee, 'coinFee': coinFee}
- def get_port_info(self, line):
- data = fill_2_hexByte(hex(int(line)), 2)
- devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
- {'IMEI': self._device['devNo'], "funCode": '15', 'data': data})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
- leftTime = int(data[4:8], 16)
- if data[8:12] == 'FFFF':
- power = 0
- else:
- power = int(data[8:12], 16)
- if data[12:16] == 'FFFF':
- elec = 0
- else:
- elec = round(int(data[12:16], 16) * 0.01, 2)
- if data[16:20] == 'FFFF':
- surp = 0
- else:
- surp = int(data[16:20], 16)
- result = {}
- result['power'] = power
- port = "%.2X" % int(line)
- try:
- payload = {"IMEI": self._device['devNo'],
- "data": port,
- "funCode": "88"}
- data = self.send_mqtt(data=payload)
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- lineInfo =ctrInfo.get(str(line), {})
-
- orderType = data.get('order_type')
- if orderType == 'com_start':
- # result['usedElec'] = round(data.get('elec', 0) / 3600000.0, 4) or 0
- # result['needElec'] = round(data['elecMax'] / 3600000.0, 2)
-
- timeFee = data['balance'] * 0.1 * round(float(data.get('time', 0)) / float(data['timeMax']), 2)
- elecFee = data['balance'] * 0.1 * round(float(data.get('elec', 0)) / float(data['elecMax']), 2)
- result['consumeMoney'] = round(max(timeFee, elecFee), 2)
- result['leftMoney'] = round(data['balance'] * 0.1 - result['consumeMoney'], 2)
-
- result['usedTime'] = round((time.time() - data['sts'] + 59) / 60)
-
- elif orderType == 'id_start':
- result['usedElec'] = round(data.get('elec', 0) / 3600000.0, 4) or 0
- # result['needElec'] = round(data['elecMax'] / 3600000.0, 2)
- # result['leftElec'] = round(data['elecMax'] / 3600000.0, 2)
- order = ConsumeRecord.objects.filter(startKey=data.get('order_id')).first() # type:ConsumeRecord
- if order:
- coins = round(order.coin, 2)
- timeFee = coins * round(float(data.get('time', 0)) / float(data['timeMax']), 2)
- elecFee = coins * round(float(data.get('elec', 0)) / float(data['elecMax']), 2)
- result['consumeMoney'] = round(max(timeFee, elecFee), 2)
- result['leftMoney'] = round(coins - result['consumeMoney'], 2)
- result['usedTime'] = round((time.time() - data['sts'] + 59) / 60)
-
-
- result['cardNo'] = '{}'.format(int(data.get('cardNo'), 16))
- card = Card.objects.filter(cardNo=result['cardNo']).first()
- if card:
- result['cardName'] = card.cardName or card.nickName
-
- result['usedTime'] = round((time.time() - data['sts'] + 59) / 60)
- result['startTime'] = Arrow.utcfromtimestamp(data['sts']).format('MM-DD HH:mm:ss')
-
- # 跳过后面的流水处理
- # result['skipPipelineProcessing'] = True
- else:
- if lineInfo['consumeType'] == 'coin':
- result['leftTime'] = leftTime
- result['leftElec'] = elec
- except Exception:
- import traceback
- logger.info(traceback.format_exc())
- return result
- def get_port_status(self, force = False):
- if force:
- return self.get_port_status_from_dev()
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- statusDict = {}
- if not ctrInfo.has_key('allPorts'):
- self.get_port_status_from_dev()
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- allPorts = ctrInfo.get('allPorts', 10)
- # allPorts 有的时候会为0, 这个时候强制设置为10
- if allPorts == 0:
- allPorts = 10
- for ii in range(allPorts):
- tempDict = ctrInfo.get(str(ii + 1), {})
- if tempDict.has_key('status'):
- statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
- elif tempDict.has_key('isStart'):
- if tempDict['isStart']:
- statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
- else:
- statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
- else:
- statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
- allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
- Device.update_dev_control_cache(self._device['devNo'],
- {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
- return statusDict
- def get_port_status_from_dev(self):
- devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
- {'IMEI': self._device['devNo'], "funCode": '0F', 'data': '00'})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
- result = {}
- portNum = int(data[2:4], 16)
- portData = data[4::]
- ii = 0
- while ii < portNum:
- port = int(portData[ii * 4:ii * 4 + 2], 16)
- statusTemp = portData[ii * 4 + 2:ii * 4 + 4]
- if statusTemp == '01':
- status = {'status': Const.DEV_WORK_STATUS_IDLE}
- elif statusTemp == '02':
- status = {'status': Const.DEV_WORK_STATUS_WORKING}
- elif statusTemp == '03':
- status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
- elif statusTemp == '04':
- status = {'status': Const.DEV_WORK_STATUS_FAULT}
- ii += 1
- result[str(port)] = status
- allPorts, usedPorts, usePorts = self.get_port_static_info(result)
- Device.update_dev_control_cache(self._device['devNo'],
- {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
- # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- for strPort, info in result.items():
- if ctrInfo.has_key(strPort):
- ctrInfo[strPort].update({'status': info['status']})
- else:
- ctrInfo[strPort] = info
- Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
- return result
- def lock_unlock_port(self, port, lock = True):
- lockStr = '00' if lock else '01'
- portStr = fill_2_hexByte(hex(int(port)), 2)
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], "funCode": '0C', 'data': portStr + lockStr})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- if lock:
- Device.update_dev_control_cache(self._device['devNo'],
- {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
- else:
- Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
- def active_deactive_port(self, port, active):
- if not active:
- self.stop_charging_port(port)
- devInfo = Device.get_dev_control_cache(self._device['devNo'])
- portCtrInfo = devInfo.get(str(port), {})
- portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE,
- 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
- newValue = {str(port): portCtrInfo}
- Device.update_dev_control_cache(self._device['devNo'], newValue)
- else:
- raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})
- def stop_charging_port(self, port):
- portStr = fill_2_hexByte(hex(int(port)), 2)
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], "funCode": '0D', 'data': portStr + '00'}, timeout=7)
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- port = int(data[2:4], 16)
- leftTime = int(data[4:8], 16)
- result = {'port': port, 'leftTime': leftTime}
- self._postpaidProcessing(result)
- return result
- # 获取设备配置参数
- def get_dev_setting(self):
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], "funCode": '1E', 'data': '00'})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- confData = data[2:-2]
- coinMin = int(confData[0:4], 16)
- cardMin = int(confData[4:8], 16)
- coinElec = int(confData[8:10], 16)
- cardElec = int(confData[10:12], 16)
- cst = int(confData[12:14], 16)
- powerMax1 = int(confData[14:18], 16)
- powerMax2 = int(confData[18:22], 16)
- powerMax3 = int(confData[22:26], 16)
- powerMax4 = int(confData[26:30], 16)
- power2Ti = int(confData[30:32], 16)
- power3Ti = int(confData[32:34], 16)
- power4Ti = int(confData[34:36], 16)
- spRecMon = int(confData[36:38], 16)
- spFullEmpty = int(confData[38:40], 16)
- fullPowerMin = int(confData[40:42], 16)
- fullChargeTime = int(confData[42:44], 16)
- elecTimeFirst = int(confData[44:46], 16)
- dev = Device.objects.get(devNo = self._device['devNo'])
- billingType = dev.otherConf.get('billingType', 'time')
- elecFee = dev.otherConf.get('elecFee', 0.9)
- # refundProtection = dev.otherConf.get('refundProtection', 0)
- refundProtectionTime = dev.otherConf.get('refundProtectionTime', 5)
- # 为了预防万一,这里顺便把数据库的数据也更新一下,主要是以设备为准的数据,更新下
- dev.otherConf.update({'cardMin': cardMin})
- try:
- dev.save()
- except Exception, e:
- pass
- deviceConf = dev.otherConf.get('deviceConfigs', {})
- resultDict = {
- 'coinMin': coinMin,
- 'cardMin': cardMin,
- 'remoteMin': deviceConf.get('remoteMin', 240),
- 'coinElec': coinElec,
- 'cardElec': cardElec,
- 'remoteElec': deviceConf.get('remoteElec', 10),
- 'cst': cst,
- 'powerMax1': powerMax1,
- 'powerMax2': powerMax2,
- 'powerMax3': powerMax3,
- 'powerMax4': powerMax4,
- 'power2Ti': power2Ti,
- 'power3Ti': power3Ti,
- 'power4Ti': power4Ti,
- 'spRecMon': spRecMon,
- 'spFullEmpty': spFullEmpty,
- 'fullPowerMin': fullPowerMin,
- 'fullChargeTime': fullChargeTime,
- 'elecTimeFirst': elecTimeFirst,
- 'billingType': billingType,
- 'elecFee': elecFee,
- 'refundProtectionTime': refundProtectionTime
- }
- self.do_update_configs(resultDict)
- consumeInfo = self.get_dev_consume_count()
- resultDict.update(consumeInfo)
- deviceInfo = self.get_real_time_device_info()
- resultDict.update(deviceInfo)
- postpaid_price_rules = self.get_postpaid_price_rules()
- resultDict.update(postpaid_price_rules)
- return resultDict
- # 设置设备配置参数
- def set_dev_setting(self, setConf):
- data = ''
- data += fill_2_hexByte(hex(int(setConf['coinMin'])), 4)
- data += fill_2_hexByte(hex(int(setConf['cardMin'])), 4)
- data += fill_2_hexByte(hex(int(setConf['coinElec'])), 2)
- data += fill_2_hexByte(hex(int(setConf['cardElec'])), 2)
- data += fill_2_hexByte(hex(int(setConf['cst'])), 2)
- data += fill_2_hexByte(hex(int(setConf['powerMax1'])), 4)
- data += fill_2_hexByte(hex(int(setConf['powerMax2'])), 4)
- data += fill_2_hexByte(hex(int(setConf['powerMax3'])), 4)
- data += fill_2_hexByte(hex(int(setConf['powerMax4'])), 4)
- data += fill_2_hexByte(hex(int(setConf['power2Ti'])), 2)
- data += fill_2_hexByte(hex(int(setConf['power3Ti'])), 2)
- data += fill_2_hexByte(hex(int(setConf['power4Ti'])), 2)
- data += fill_2_hexByte(hex(int(setConf['spRecMon'])), 2)
- data += fill_2_hexByte(hex(int(setConf['spFullEmpty'])), 2)
- data += fill_2_hexByte(hex(int(setConf['fullPowerMin'])), 2)
- data += fill_2_hexByte(hex(int(setConf['fullChargeTime'])), 2)
- data += fill_2_hexByte(hex(int(setConf['elecTimeFirst'])), 2)
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], "funCode": '18', 'data': data})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- dev = Device.objects.get(devNo = self._device['devNo'])
- dev.otherConf.update({'billingType': setConf['billingType']})
- dev.otherConf.update({'elecFee': setConf['elecFee']})
- dev.otherConf.update({'refundProtectionTime': setConf['refundProtectionTime']})
- dev.otherConf.update({'cardMin': setConf['cardMin']})
- dev.otherConf.update({'remoteMin': setConf['remoteMin']})
- dev.otherConf.update({'remoteElec': setConf['remoteElec']})
- dev.otherConf.get('deviceConfigs', {}).update({'remoteMin': setConf['remoteMin']})
- dev.otherConf.get('deviceConfigs', {}).update({'remoteElec': setConf['remoteElec']})
- dev.save()
- Device.invalid_device_cache(self.device.devNo)
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- # 更新一次参数到数据库中
- self.get_dev_setting()
- def response_use_card(self, res, balance):
- data = '55061001'
- data = data + res + fill_2_hexByte(hex(int(balance * 10)), 4)
- devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
- {'IMEI': self._device['devNo'], "funCode": '10', 'data': data})
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1: # 等于1的时候,说明服务器和远程模块通讯OK,响应已经收到,不需要异常处理
- pass
- def set_device_function_param(self, request, lastSetConf):
- coinMin = request.POST.get('coinMin', None)
- cardMin = request.POST.get('cardMin', None)
- remoteMin = request.POST.get('remoteMin', None)
- coinElec = request.POST.get('coinElec', None)
- cardElec = request.POST.get('cardElec', None)
- remoteElec = request.POST.get('remoteElec', None)
- cst = request.POST.get('cst', None)
- powerMax1 = request.POST.get('powerMax1', None)
- powerMax2 = request.POST.get('powerMax2', None)
- powerMax3 = request.POST.get('powerMax3', None)
- powerMax4 = request.POST.get('powerMax4', None)
- power2Ti = request.POST.get('power2Ti', None)
- power3Ti = request.POST.get('power3Ti', None)
- power4Ti = request.POST.get('power4Ti', None)
- spRecMon = request.POST.get('spRecMon', None)
- spFullEmpty = request.POST.get('spFullEmpty', None)
- fullPowerMin = request.POST.get('fullPowerMin', None)
- fullChargeTime = request.POST.get('fullChargeTime', None)
- elecTimeFirst = request.POST.get('elecTimeFirst', None)
- billingType = request.POST.get('billingType', None)
- elecFee = request.POST.get('elecFee', None)
- refundProtection = request.POST.get('refundProtection', None)
- refundProtectionTime = request.POST.get('refundProtectionTime', None)
- lowPowerDetectionTime = request.POST.get('lowPowerDetectionTime', None)
- lowPowerDetectionSwitch = request.POST.get('lowPowerDetectionSwitch', None)
- lowPowerDetectionPower = request.POST.get('lowPowerDetectionPower', None)
- # 这几个参数是墨小智V3特有的
- stWTime = request.POST.get('stWTime', None)
- temThre = request.POST.get('temThre', None)
- freeUse = request.POST.get('freeUse', None)
- relayMasterSwitch = request.POST.get('relayMasterSwitch', None)
- if coinMin:
- lastSetConf.update({'coinMin': int(coinMin)})
- if cardMin:
- lastSetConf.update({'cardMin': int(cardMin)})
- if remoteMin:
- lastSetConf.update({'remoteMin': int(remoteMin)})
- if coinElec:
- lastSetConf.update({'coinElec': int(coinElec)})
- if cardElec:
- lastSetConf.update({'cardElec': int(cardElec)})
- if remoteElec:
- lastSetConf.update({'remoteElec': int(remoteElec)})
- if cst:
- lastSetConf.update({'cst': int(cst)})
- if powerMax1:
- lastSetConf.update({'powerMax1': int(powerMax1)})
- if powerMax2:
- lastSetConf.update({'powerMax2': int(powerMax2)})
- if powerMax3:
- lastSetConf.update({'powerMax3': int(powerMax3)})
- if powerMax4:
- lastSetConf.update({'powerMax4': int(powerMax4)})
- if power2Ti:
- lastSetConf.update({'power2Ti': int(power2Ti)})
- if power3Ti:
- lastSetConf.update({'power3Ti': int(power3Ti)})
- if power4Ti:
- lastSetConf.update({'power4Ti': int(power4Ti)})
- if spRecMon:
- lastSetConf.update({'spRecMon': int(spRecMon)})
- if spFullEmpty:
- lastSetConf.update({'spFullEmpty': int(spFullEmpty)})
- if fullPowerMin:
- lastSetConf.update({'fullPowerMin': int(fullPowerMin)})
- if fullChargeTime:
- lastSetConf.update({'fullChargeTime': int(fullChargeTime)})
- if elecTimeFirst:
- lastSetConf.update({'elecTimeFirst': int(elecTimeFirst)})
- if billingType:
- lastSetConf.update({'billingType': billingType})
- if elecFee:
- lastSetConf.update({'elecFee': elecFee})
- if refundProtection:
- lastSetConf.update({'refundProtection': int(refundProtection)})
- if refundProtectionTime:
- lastSetConf.update({'refundProtectionTime': int(refundProtectionTime)})
- if lowPowerDetectionTime:
- lastSetConf.update({'lowPowerDetectionTime': int(lowPowerDetectionTime)})
- if lowPowerDetectionSwitch:
- lastSetConf.update({'lowPowerDetectionSwitch': int(lowPowerDetectionSwitch)})
- if lowPowerDetectionPower:
- lastSetConf.update({'lowPowerDetectionPower': int(lowPowerDetectionPower)})
- # 这几个参数是墨小智V3特有的
- if stWTime:
- lastSetConf.update({'stWTime': int(stWTime)})
- if temThre:
- lastSetConf.update({'temThre': int(temThre)})
- if freeUse:
- lastSetConf.update({'freeUse': int(freeUse)})
- self.set_dev_setting(lastSetConf)
- # 新增总继电器开关
- if relayMasterSwitch:
- try:
- self.relay_master_switch(relayMasterSwitch)
- except Exception as e:
- pass
- def handle_clear_start_error(self, port):
- dealer = Dealer.objects.get(id = self._device["ownerId"])
- if not dealer or not dealer.managerialOpenId:
- return
- group = Group.get_group(self._device["groupId"])
- self.lock_unlock_port(port, lock = False)
- notifyData = {
- "title": "设备故障报警解除",
- "device": u"{gNum}组-{lc}-{port}端口".format(gNum = self._device["groupNumber"],
- lc = self._device["logicalCode"],
- port = port),
- "location": u"{address}-{groupName}".format(address = group["address"], groupName = group["groupName"]),
- "fault": u"当前端口已被正常启动,端口故障解除",
- "notifyTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- }
- task_caller(
- func_name = 'report_to_dealer_via_wechat',
- openId = dealer.managerialOpenId,
- dealerId = str(dealer.id),
- templateName = "device_fault",
- **notifyData
- )
- self.lock_unlock_port(port, lock = False)
- def handle_out_start_error(self, port):
- dealer = Dealer.objects.get(id = self._device["ownerId"])
- if not dealer or not dealer.managerialOpenId:
- return
- group = Group.get_group(self._device["groupId"])
- times = Device.get_error_start_times(self._device["devNo"], port)
- self.lock_unlock_port(port, lock = True)
- notifyData = {
- "title": u"注意,您的设备可能发生故障!",
- "device": u"{gNum}组-{lc}-{port}端口".format(gNum = self._device["groupNumber"],
- lc = self._device["logicalCode"],
- port = port),
- "location": u"{address}-{groupName}".format(address = group["address"], groupName = group["groupName"]),
- "fault": u"当前设备端口连续启动 {times} 失败,目前该端口已经被自动禁用,请注意该端口是否发生故障".format(times = times),
- "notifyTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- }
- task_caller(
- func_name = 'report_to_dealer_via_wechat',
- openId = dealer.managerialOpenId,
- dealerId = str(dealer.id),
- templateName = "device_fault",
- **notifyData
- )
- # 麦总的告警3次触发,同时锁定设备,为避免解锁设备之后 再次触发 这个地方需要将其缓存清空
- Device.delete_error_start_times(self._device["devNo"], port)
- @SmartBox.check_device_features(device_features=["fun_code_30_31"])
- def relay_master_switch(self,relayMasterSwitch=1):
- if relayMasterSwitch == 1:
- data = "01"
- else:
- data = "00"
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], 'funCode': '31', 'data': data},timeout=7)
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- dev = Device.objects.get(devNo=self._device['devNo'])
- dev.otherConf.update({'relayMasterSwitch': relayMasterSwitch})
- dev.save()
- Device.invalid_device_cache(dev.devNo)
- @SmartBox.check_device_features(device_features=["fun_code_30_31"], no_features_to_return={"haveStatus": False})
- def get_real_time_device_info(self):
- try:
- devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
- {'IMEI': self._device['devNo'], 'funCode': '30', 'data': '00'},timeout=7)
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- except Exception:
- return {"haveStatus": False}
- data = devInfo.get("data")
- maxPower = int(data[8:12], 16)
- elec = int(data[12:16], 16)
- maxTemperature = int(data[16:18], 16)
- base = -1 if int(data[18:20], 16) == 1 else 1
- temperature = int(data[20:22], 16) * base
- fire = int(data[22:24], 16)
- smoke = int(data[24:26], 16)
- overheat = int(data[26:28], 16)
- overload = int(data[28:30], 16)
- relayMasterSwitch = int(data[30:32], 16)
- return {"haveStatus": True, "maxPower": maxPower, "elec": elec, "maxTemperature": maxTemperature,
- "temperature": temperature,
- "fire": fire, "smoke": smoke, "overheat": overheat, "overload": overload,
- "relayMasterSwitch": relayMasterSwitch, }
- def _response_to_2D(self, sessionId):
- """
- 回复 充电桩主板的2D指令 否则会重复上报
- :param sessionId:
- :return:
- """
- result = MessageSender.send(
- device=self.device,
- cmd=DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
- payload={
- "funCode": "2D",
- "data": '55082D01' + sessionId,
- "IMEI": self.device.devNo
- }
- )
- def _response_to_27(self,obj,balance):
- data = obj.event_data
- cardNoHex = data["sourceData"][22: 30]
- port = data["sourceData"][8: 10]
- money = balance
- time = '0005'
- elec = '0000'
- session_id = data["sourceData"][38: 46]
- result = MessageSender.send(
- device=self.device,
- cmd=DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
- payload={
- "funCode": "27",
- "data": 'AA0F2701' + port + money + time + elec + session_id + '03',
- "IMEI": self.device.devNo
- }
- )
- def _check_package(self, package):
- """
- 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
- :param package:
- :return:
- """
- # 按时间计费
- coins = float(package.get('coins', 0))
- if coins == 0:
- raise ServiceException({"result": 2, "description": u"经销商套餐配置错误, 金币不能为0"})
- packageTime = float(package.get("time", 0))
- if packageTime == 0:
- raise ServiceException({"result": 2, "description": u"经销商套餐配置错误, 时间参数或电量参数不能为0"})
- device_configs = self.get_device_configs()
- remoteMin = device_configs.get('remoteMin', 240)
- remoteElec = device_configs.get('remoteElec', 10)
- elec = remoteElec * 0.1 * coins
- unit = package.get("unit", u"分钟")
- if unit == u"小时":
- _time = int(packageTime * 60)
- elif unit == u"天":
- _time = int(packageTime * 24 * 60)
- elif unit == u"秒":
- _time = int(packageTime / 60)
- elif unit == u"分钟":
- _time = int(packageTime)
- elif unit == u'度':
- _time = int(remoteMin * package.get('coins'))
- elec = package.get('time')
- else:
- raise ServiceException({"result": 2, "description": u"经销商套餐单位配置错误,请联系经销商修改套餐设置"})
- return _time, elec
- def send_mqtt(self, data=None, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, otherData=None):
- """
- 发送mqtt 指令默认210 返回data
- """
- if 'cmd' not in data:
- data.update({'cmd': cmd})
- if 'IMEI' not in data:
- data.update({'IMEI': self.device.devNo})
- result = MessageSender.send(self.device, cmd,data)
- if "rst" in result and result["rst"] != 0:
- if result["rst"] == -1:
- raise ServiceException(
- {"result": 2, "description": u"该设备正在玩命找网络,请您稍候再试", "rst": -1})
- elif result["rst"] == 1:
- raise ServiceException(
- {"result": 2, "description": u"该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能", "rst": 1})
- else:
- if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]:
- return
- return result
- def get_account_rule(self, timeMax, elecMax):
- #秒
- timeMax = int(timeMax * 60)
- # 度 > 瓦
- elecMax = int(elecMax * 3600000)
- device_configs = self.get_device_configs()
- powerMax1 = device_configs.get('powerMax1', 200)
- power1Ti = device_configs.get('power1Ti', 100)
- powerMax2 = device_configs.get('powerMax2', 300)
- power2Ti = device_configs.get('power2Ti', 75)
- powerMax3 = device_configs.get('powerMax3', 400)
- power3Ti = device_configs.get('power3Ti', 50)
- powerMax4 = device_configs.get('powerMax4', 500)
- power4Ti = device_configs.get('power4Ti', 25)
- return {
- 'timeMax': timeMax,
- 'elecMax': elecMax,
- 'accountRule': {
- 'powerStep': [
- {'max': powerMax1,
- 'ratio': power1Ti},
- {'max': powerMax2,
- 'ratio': power2Ti},
- {'max': powerMax3,
- 'ratio': power3Ti},
- {'max': powerMax4,
- 'ratio': power4Ti},
- ]
- }
- }
- def start_device_realiable(self, order):
- if order.orderNo[:10] == self.device.ownerId[-10:]: # 此时为远程上分 先停一次
- self.stop_charging_port(order.used_port)
- attachParas = order.attachParas
- package = order.package
- if attachParas is None:
- raise ServiceException({"result": 2, "description": u"请您选择合适的充电线路、电池类型信息"})
- if not attachParas.has_key("chargeIndex"):
- raise ServiceException({"result": 2, "description": u"请您选择合适的充电线路"})
- port = int(attachParas["chargeIndex"])
- coins = package.get("coins", 0)
- _time, elec = self._check_package(package)
- rule = self.get_account_rule(_time, elec)
- data = {
- 'order_type': 'com_start',
- 'funCode': '27',
- 'port': port,
- 'result': Cmd.SUCCESS_00,
- 'balance': int(coins * 10.0),
- 'order_id': order.orderNo,
- 'packageTime': _time,
- }
- data.update(rule)
- result = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = data,
- timeout = 120)
- try:
- order.servicedInfo.update(startData=data)
- order.save()
- except:
- pass
- return result
- @property
- @SmartBox.check_device_features(device_features=["Postpaid"],no_features_to_return=False)
- def is_postpaid(self):
- return True
- @SmartBox.check_device_features(device_features = ["Postpaid"])
- def check_order_state(self, openId):
- """
- 通过 openId 以及设备来鉴别 订单
- :param openId:
- :return:
- """
- dealerId = self.device.ownerId
- devTypeCode = self.device.devType.get("code")
- return ConsumeRecord.objects.filter(ownerId = dealerId,
- openId = openId,
- devTypeCode = devTypeCode,
- status__ne = "finished",
- isNormal = True,
- attachParas__isPostpaid = True).first()
- @SmartBox.check_device_features(device_features=["Postpaid"])
- def _postpaidProcessing(self, result):
- "leftTime" in result and result.pop("leftTime")
- if "power" in result: # 刚启动power为0,serverProcess校验会直接结束掉,需要等设备计量的数据正常上报上来,此处改为字符串"0"
- if result["power"] == 0:
- result["power"] = "0"
- @SmartBox.check_device_features(device_features=["Postpaid"])
- def set_postpaid_price_rules(self, configs):
- postpaidConfigs = {}
- postpaidConfigs["postpaidBaseTime"] = configs.get("postpaidBaseTime", 30)
- postpaidConfigs["postpaidMaxTime"] = configs.get("postpaidMaxTime", 720)
- postpaidConfigs["postpaidPower1"] = configs.get("postpaidPower1", 150)
- postpaidConfigs["postpaidPower2"] = configs.get("postpaidPower2", 250)
- postpaidConfigs["postpaidPower3"] = configs.get("postpaidPower3", 350)
- postpaidConfigs["postpaidPower4"] = configs.get("postpaidPower4", 500)
- postpaidConfigs["postpaidPowerPrice1"] = configs.get("postpaidPowerPrice1", 0.28)
- postpaidConfigs["postpaidPowerPrice2"] = configs.get("postpaidPowerPrice2", 0.35)
- postpaidConfigs["postpaidPowerPrice3"] = configs.get("postpaidPowerPrice3", 0.48)
- postpaidConfigs["postpaidPowerPrice4"] = configs.get("postpaidPowerPrice4", 0.66)
- dev = Device.objects.get(devNo=self.device.devNo)
- dev.otherConf.update({"postpaidConfigs":postpaidConfigs})
- dev.save()
- Device.invalid_device_cache(self.device.devNo)
- @SmartBox.check_device_features(device_features=["Postpaid"],no_features_to_return={})
- def get_postpaid_price_rules(self):
- otherConf = self.device["otherConf"]
- postpaidConfigs = otherConf.get("postpaidConfigs", {})
- if not postpaidConfigs:
- self.set_postpaid_price_rules({})
- dev = Device.objects.get(devNo=self.device.devNo)
- otherConf = dev.otherConf
- postpaidConfigs = otherConf.get("postpaidConfigs", {})
- return postpaidConfigs
- def stop_by_order(self, port, orderNo):
- order = ConsumeRecord.objects.filter(orderNo=orderNo, isNormal=True, status__ne="finished").first()
- if order:
- try:
- self.stop_charging_port(port)
- except Exception:
- pass
- self.deal_order_finish(order)
- def do_postpaid_finished_event(self, order):
- now = datetime.datetime.now()
- start_time = order.startTime
- duration = int((now-start_time).total_seconds())
- device_event = {
- "order_type": "com_start",
- "leftElec": 0,
- "duration": duration,
- "reason": "90",
- "order_id": order.orderNo,
- "leftTime": 0,
- "sts": Arrow.fromdatetime(order.startTime, tzinfo=settings.TIME_ZONE).timestamp,
- "fts": int(time.time()),
- "elec": 0,
- "status": "finished",
- "port": order.used_port,
- }
- eventer = ActionDeviceBuilder.create_eventer(self.device)
- event = eventer.getEvent(device_event)
- event.do()
- def deal_order_finish(self, order):
- if self.is_postpaid: # 后付费订单 后付费数据处理过 没有leftTime
- self.do_postpaid_finished_event(order)
- else:
- self.do_finished_event(order)
- def do_finished_event(self, order):
- pass
- def response_card(self, res, balance, fee, oper, cardNoHex, isVir=False, virtual_card_id=None):
- if isVir:
- res = int(res)
- count = int(balance) * 10
- fee = int(fee) * 10
- oper = int(oper)
- MessageSender.send(
- device=self.device,
- cmd=220,
- payload={
- "res": res,
- "balance": count,
- "card_cst": fee,
- "card_ope": oper,
- "card_id": cardNoHex,
- "funCode": "10",
- "isVir": isVir,
- "virtual_card_id": virtual_card_id
- }
- )
- else:
- res = int(res)
- balance = int(balance) * 10
- fee = int(fee) * 10
- oper = int(oper)
- MessageSender.send(
- device=self.device,
- cmd=220,
- payload={
- "res": res,
- "balance": balance,
- "card_cst": fee,
- "card_ope": oper,
- "card_id": cardNoHex,
- "funCode": "10",
- "isVir": isVir
- }
- )
- def get_device_configs(self):
- dev = Device.get_dev(self.device.devNo)
- deviceConfigs = dev.get("otherConf", {}).get("deviceConfigs", {})
- return deviceConfigs
- def do_update_configs(self, updateDict):
- dev = Device.objects.get(devNo=self.device.devNo)
- deviceConfigs = dev.otherConf.get("deviceConfigs", {})
- deviceConfigs.update(updateDict)
- dev.otherConf['deviceConfigs'] = deviceConfigs
- dev.save()
- Device.invalid_device_cache(self.device.devNo)
-
- def check_dev_status(self, attachParas = None):
- port = attachParas.get('chargeIndex')
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- lineInfo = ctrInfo.get(port)
- if lineInfo.get('status') == Const.DEV_WORK_STATUS_WORKING:
- raise ServiceException({"result": 2, "description": "不支持续充"})
- elif lineInfo.get('status') == Const.DEV_WORK_STATUS_FAULT:
- raise ServiceException({"result": 2, "description": "端口故障"})
- elif lineInfo.get('status') == Const.DEV_WORK_STATUS_FORBIDDEN:
- raise ServiceException({"result": 2, "description": "该端口已被禁用"})
-
- class IdCardStartAckEvent(AckEvent):
- pass
|