123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import re
- import time
- import logging
- from decimal import Decimal
- from apilib.monetary import RMB
- from apps.web.common.models import TempValues
- from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT
- 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.device.models import Device
- from apps.web.user.models import Card
- logger = logging.getLogger(__name__)
- class ChangyuanFive(SmartBox):
- FINISH_REASON_MAP = {
- '01': '设备充满自停或拔掉插头',
- '02': '超功率停止',
- '03': '时间用完停止',
- '04': '远程停止',
- '05': '预付卡的扣费金额用完',
- '06': '到达安全充电时间',
- '07': '正常结束充电',
- '09': '电量超限',
- '10': '设备充满停止充电'
- }
- PAY_TYPE_MAP = {
- 'cash': '01',
- 'vCard': '02',
- 'coin': '03'
- }
- DEFAULT_DISCOUNT = '0'
-
- @staticmethod
- def _parse_D0_data(data):
- '''
- 解析 设备参数 返还的数据
- :param data:
- :return:
- '''
- powerTime1 = ChangyuanFive.decode_str(data[6:10])
- powerTime2 = ChangyuanFive.decode_str(data[10:14])
- powerTime3 = ChangyuanFive.decode_str(data[14:18])
- powerTime4 = ChangyuanFive.decode_str(data[18:22])
- power1 = ChangyuanFive.decode_str(data[22:26])
- power2 = ChangyuanFive.decode_str(data[26:30])
- power3 = ChangyuanFive.decode_str(data[30:34])
- power4 = ChangyuanFive.decode_str(data[34:38])
- noloadPower = ChangyuanFive.decode_str(data[38:40])
- noloadTime = ChangyuanFive.decode_str(data[40:42])
- volume = ChangyuanFive.decode_str(data[42:44])
- cardFee = ChangyuanFive.decode_str(data[44:48], ratio=0.01)
- floatPower = ChangyuanFive.decode_str(data[48:50])
- floatTime = ChangyuanFive.decode_str(data[50:54])
- cardFree = True if data[54:56] == 'AA' else False
- return locals()
- @staticmethod
- def _parse_D3_data(data):
- """
- 解析同步结果指令上报
- :param data:
- :return:
- """
- cardType = data[6:8]
- cardNo = data[8:16]
- cardBalance = RMB(int(data[16:22], 16))
- result = True if data[22:24] == 'AA' else False
- sid = int(data[24:28], 16)
- if cardType == '01':
- cardBalance = cardBalance * 0.01
- return {
- "cardType": cardType,
- "cardNo": cardNo,
- "cardBalance": cardBalance,
- "result": result,
- "sid": sid
- }
- @staticmethod
- def _parse_D4_data(data):
- """
- 解析 卡余额同步 结果
- :param data:
- :type data:
- :return:
- :rtype:
- """
- cardType = data[6:8]
- cardNo = data[8:16]
- cardBalance = RMB(int(data[16:22], 16))
- if cardType == '01':
- cardBalance = cardBalance * 0.01
- return {
- "cardType": cardType,
- "cardNo": cardNo,
- "cardBalance": cardBalance
- }
- @staticmethod
- def _parse_D7_data(data):
- '''
- 火警数据解析
- :param data:
- :type data:
- :return:
- :rtype:
- '''
- return {'data': data[6:8]}
- @staticmethod
- def _parse_D8_data(data):
- '''
- 定时上传 桩的工作状态
- :param data:
- :type data:
- :return:
- :rtype:
- '''
- if len(data) == 18:
- # voltage = int(data[6:10], 16) / 10.0
- temperature = int(data[8:10], 16)
- if data[6:8] == '01':
- temperature = temperature * -1
- defaultPortInfo = {'status': Const.DEV_WORK_STATUS_IDLE}
- portInfo = {}.fromkeys(['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', ], defaultPortInfo)
- return {'temperature': temperature, 'portInfo': portInfo}
- else:
- all_port_status = ChangyuanFive.decode_long_hex_to_list(data[6:26], transformer=False)
- all_port_power = ChangyuanFive.decode_long_hex_to_list(data[26:66],split=4)
- all_port_left = ChangyuanFive.decode_long_hex_to_list(data[66:106],split=4)
- temperature = int(data[108:110], 16)
- if data[106:108] == '01':
- temperature = temperature * -1
- portInfo = {}
- for i in xrange(len(all_port_status)):
- item = {}
- item['power'] = all_port_power[i]
- item['leftTime'] = all_port_left[i]
- tempStatus = all_port_status[i]
- if tempStatus == '00':
- status = Const.DEV_WORK_STATUS_IDLE
- elif tempStatus == '01':
- status = Const.DEV_WORK_STATUS_WORKING
- elif tempStatus == '11':
- status = Const.DEV_WORK_STATUS_WORKING
- del item['leftTime']
- item['leftMoney'] = round(all_port_left[i] * 0.01, 2)
- else:
- status = Const.DEV_WORK_STATUS_IDLE
- item['status'] = status
- portInfo[str(i + 1)] = item.copy()
- return {'temperature': temperature, 'portInfo': portInfo}
- @staticmethod
- def _parse_D9_data(data):
- '''
- 充电开始 上传
- :param data:
- :type data:
- :return:
- :rtype:
- '''
- power = ChangyuanFive.decode_str(data[20:24])
- coins = ChangyuanFive.decode_str(data[24:28], ratio=0.01)
- port = ChangyuanFive.decode_str(data[28:30])
- payType = data[30:32]
- if payType == '00': # 次卡
- cardNo = data[6:14]
- cardType = "00"
- cardBalance = ChangyuanFive.decode_str(data[14:20])
- needTime = ChangyuanFive.decode_str(data[32:36])
- elif payType == '01': # 扫码
- needTime = ChangyuanFive.decode_str(data[32:36])
- elif payType == '02': # 投币
- needTime = ChangyuanFive.decode_str(data[32:36])
- elif payType == '03': # 预付卡
- cardNo = data[6:14]
- cardType = "01"
- cardBalance = ChangyuanFive.decode_str(data[14:20], ratio=0.01)
- leftMoney = ChangyuanFive.decode_str(data[32:36], ratio=0.01)
- elif payType == '04':
- cardNo = data[6:14]
- cardType = "0A"
- cardBalance = ChangyuanFive.decode_str(data[14:20], ratio=0.01)
- needTime = ChangyuanFive.decode_str(data[32:36])
- else:
- pass
- return locals()
- @staticmethod
- def _parse_DA_data(data):
- '''
- 充电结束上传
- :param data:
- :type data:
- :return:
- :rtype:
- '''
- port = ChangyuanFive.decode_str(data[6:8])
- reasonCode = data[8:10]
- usedElec = ChangyuanFive.decode_str(data[10:14], ratio=0.001)
- left = ChangyuanFive.decode_str(data[14:18])
- # 在线卡版本设备充满自停和插座掉落分离开
- # if ChangyuanFive.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD:
- # if reasonCode == '01':
- # reasonCode = '10'
- reason = ChangyuanFive.FINISH_REASON_MAP.get(reasonCode, u'未知停止方式')
- return locals()
- @staticmethod
- def _parse_DE_data(data):
- '''
- 实体卡返费 的指令
- :param data:
- :type data:
- :return:
- :rtype:
- '''
- cardNo = data[6:14]
- beforeRefund = int(data[14:20], 16) / 100.0
- refund = int(data[20:24], 16) / 100.0
- afterRefund = int(data[24:30], 16) / 100.0
- return locals()
- @staticmethod
- def _parse_F0_data(data):
- cardType = data[6:8]
- cardNo = data[8:16]
- port = data[16:18]
- return locals()
- @staticmethod
- def _parse_COMMON_data(data):
- '''
- 解析 通用的数据返回 一般表示成功还是失败
- :param data:
- :type data:
- :return:
- :rtype:
- '''
- return True if data[6:10] == '4F4B' else False
- def _send_data(self, funCode, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=MQTT_TIMEOUT.NORMAL):
- result = MessageSender.send(device=self.device, cmd=cmd, payload={
- 'IMEI': self.device.devNo,
- 'funCode': funCode,
- 'data': data
- }, timeout=timeout)
- if result['rst'] != 0:
- if result['rst'] == -1:
- raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请稍候再试'})
- elif result['rst'] == 1:
- raise ServiceException({'result': 2, 'description': u'充电桩主板连接故障'})
- else:
- raise ServiceException({'result': 2, 'description': u'系统错误'})
- return result
- def _start(self, payMoney, port, time='0000', discount='0'):
- '''
- 启动设备
- :param payMoney:
- :return:
- '''
- data = ''
- data += self.encode_str(payMoney, ratio=10)
- data += self.encode_str(time, length=4)
- data += self.encode_str(discount, length=1)
- data += self.encode_str(port, length=1)
- result = self._send_data('D2', data, timeout=MQTT_TIMEOUT.START_DEVICE)
- if 'data' not in result or not ChangyuanFive._parse_COMMON_data(result.get('data')):
- raise ServiceException({'result': '2', 'description': u'设备启动错误,请联系经销商协助解决(设备返回支付不成功)'})
- return result
- @staticmethod
- def transform_password(password):
- passwordHex = ''
- while password:
- passwordHex += fill_2_hexByte(hex(int(password[: 2])), 2)
- password = password[2:]
- return passwordHex
- def _set_password(self, password):
- """
- 设置设备的小区密码
- 密码是否还需要再校验,以及是否是0开头
- """
- if not password.isdigit():
- raise ServiceException({'result': '2', 'description': u'密码必须必须为0-9数字'})
- if len(password) != 10:
- raise ServiceException({'result': 0, 'description': u'密码长度必须为10位'})
- passwordHex = self.transform_password(password)
- result = self._send_data('DB', data=passwordHex)
- if 'data' not in result or not ChangyuanFive._parse_COMMON_data(result.get('data')):
- raise ServiceException({'result': '2', 'description': u'设置小区密码失败,请重新试试'})
- return result
- def _set_send_card(self, oldPassword, newPassword, FaKacardType):
- '''
- 设置卡机模式 用于重置 实体卡的小区密码
- '''
- if not oldPassword.isdigit() or not newPassword.isdigit():
- raise ServiceException({'result': '2', 'description': u'密码必须必须为0-9数字'})
- if len(oldPassword) != 10 or len(newPassword) != 10:
- raise ServiceException({'result': 0, 'description': u'密码长度必须为10位'})
- if not FaKacardType:
- raise ServiceException({'result': 0, 'description': u'请选择要发行卡的类型'})
- oldPasswordHex = self.transform_password(oldPassword)
- newPasswordHex = self.transform_password(newPassword)
- FaKacardType = self.encode_str(FaKacardType)
- result = self._send_data('DC', data=oldPasswordHex + newPasswordHex + FaKacardType)
- if 'data' not in result or not ChangyuanFive._parse_COMMON_data(result.get('data')):
- raise ServiceException({'result': '2', 'description': u'设置发卡机模式失败,请重新试试'})
- return result
- def _reboot_device(self):
- result = self._send_data('D5', '0000')
- if 'data' not in result or not ChangyuanFive._parse_COMMON_data(result.get('data')):
- raise ServiceException({'result': '2', 'description': u'设备复位错误,请重新试试'})
- return result
- def _async_card_balance(self, cardType, cardNo, asyncMoney):
- """
- 同步卡内余额
- :param cardType:
- :param cardNo:
- :param asyncMoney:
- :return:
- """
- # 如果是预付费的卡 同步的金额需要变换为分
- balance = asyncMoney if cardType == '00' else asyncMoney * 100
- # 获取随机流水号
- sidKey = '{}-{}'.format(self.device.devNo, cardNo)
- sid = TempValues.get(sidKey)
- balanceHex = self.encode_str(int(balance), length=6)
- sidHex = self.encode_str(sid, length=4)
- MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload={
- 'IMEI': self.device.devNo,
- 'funCode': 'D3',
- 'data': cardType + balanceHex + sidHex
- })
- def _ack_finished_massage(self, daid):
- return MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload={
- "IMEI": self.device.devNo,
- "data": "",
- "daid": daid,
- "funCode": "FA"})
- def _ack(self, ack_id):
- self._send_data(funCode='AK', data=ack_id, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
- # 获取10条未返费的记录 暂时未使用
- def _no_refund_record(self):
- result = self._send_data('DE', '00')
- data = result['data']
- noRefund = list()
- data = data[6: -8]
- for i in xrange(0, 120, 12):
- tempData = data[i:i + 12]
- cardNo = tempData[:8]
- amount = tempData[8:]
- if cardNo == 'FFFFFFFF' or cardNo == '00000000': continue
- amount = int(amount, 16) / 100.0
- noRefund.append({'cardNo': cardNo, 'amount': amount})
- return noRefund
- def _set_all_settings(self, settings):
- powerTime1 = settings.get('powerTime1')
- powerTime2 = settings.get('powerTime2')
- powerTime3 = settings.get('powerTime3')
- powerTime4 = settings.get('powerTime4')
- power1 = settings.get('power1')
- power2 = settings.get('power2')
- power3 = settings.get('power3')
- power4 = settings.get('power4')
- noloadPower = settings.get('noloadPower')
- noloadTime = settings.get('noloadTime')
- volume = settings.get('volume')
- cardFee = settings.get('cardFee')
- floatPower = settings.get('floatPower')
- floatTime = settings.get('floatTime')
- cardFree = settings.get('cardFree')
- #
- powerTime1 = self.check_params_range(params=powerTime1, minData=0, maxData=999, desc='第1段功率时间')
- powerTime2 = self.check_params_range(params=powerTime2, minData=0, maxData=999, desc='第2段功率时间')
- powerTime3 = self.check_params_range(params=powerTime3, minData=0, maxData=999, desc='第3段功率时间')
- powerTime4 = self.check_params_range(params=powerTime4, minData=0, maxData=999, desc='第4段功率时间')
- power1 = self.check_params_range(params=power1, minData=0, maxData=999, desc='第1段功率值')
- power2 = self.check_params_range(params=power2, minData=0, maxData=999, desc='第2段功率值')
- power3 = self.check_params_range(params=power3, minData=0, maxData=999, desc='第3段功率值')
- power4 = self.check_params_range(params=power4, minData=0, maxData=999, desc='第4段功率值')
- noloadPower = self.check_params_range(params=noloadPower, minData=0, maxData=50, desc='空载检测功率')
- noloadTime = self.check_params_range(params=noloadTime, minData=0, maxData=255, desc='空载功率检测时间')
- volume = self.check_params_range(params=volume, minData=0, maxData=8, desc='音量')
- cardFee = self.check_params_range(params=cardFee, minData=0, maxData=655, desc='预付卡预扣金额')
- floatPower = self.check_params_range(params=floatPower, minData=0, maxData=50, desc='浮动功率')
- floatTime = self.check_params_range(params=floatTime, minData=0, maxData=60000, desc='浮动功率延长时间')
- data = ''
- data += self.encode_str(powerTime1, length=4)
- data += self.encode_str(powerTime2, length=4)
- data += self.encode_str(powerTime3, length=4)
- data += self.encode_str(powerTime4, length=4)
- data += self.encode_str(power1, length=4)
- data += self.encode_str(power2, length=4)
- data += self.encode_str(power3, length=4)
- data += self.encode_str(power4, length=4)
- data += self.encode_str(noloadPower, length=2)
- data += self.encode_str(noloadTime, length=2)
- data += self.encode_str(volume, length=2)
- data += self.encode_str(cardFee, length=4, ratio=100)
- data += self.encode_str(floatPower, length=2)
- data += self.encode_str(floatTime, length=4)
- data += cardFree
- result = self._send_data('D1', data)
- if 'data' not in result or not ChangyuanFive._parse_COMMON_data(result.get('data')):
- raise ServiceException({'result': '2', 'description': u'设置设备参数错误,请联系经销商协助解决'})
- return result
- def _set_elec_price(self, elecPrice):
- """
- 设置电量单价 这个参数是模块侧的 只下发到模块驱动 不到主板
- :param elecPrice:
- :return:
- """
- elecPriceHex = "{:0>8X}".format(int(3600 * 1000 * float(elecPrice)))
- self._send_data("EP", elecPriceHex)
- # 更新参数设置
- Device.get_collection().update_one({'devNo': self.device['devNo']}, {'$set': {'otherConf.elecPrice': elecPrice}})
- Device.invalid_device_cache(self.device.devNo)
- def _get_dev_port_info(self):
- result = self._send_data('E1', '0000')
- data = result['data']
- return ChangyuanFive._parse_D8_data(data)
- @staticmethod
- def check_params_range(params, minData=None, maxData=None, desc=''):
- # type:(str,float,float,str) -> str
- '''
- 检查参数,返回字符串参数
- '''
- if params is None:
- raise ServiceException({'result': 2, 'description': u'参数错误.'})
- if not isinstance(params, Decimal):
- params = Decimal(params)
- if not minData and maxData:
- if not isinstance(maxData, Decimal):
- maxData = Decimal(maxData)
- if params <= maxData:
- return '%g' % params
- else:
- raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最大值为%g' % (desc, maxData)})
- if not maxData and minData:
- if not isinstance(minData, Decimal):
- minData = Decimal(minData)
- if minData <= params:
- return '%g' % params
- else:
- raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最小值为%g' % (desc, minData)})
- if not minData and not maxData:
- return '%g' % params
- else:
- if not isinstance(minData, Decimal):
- minData = Decimal(minData)
- if not isinstance(maxData, Decimal):
- maxData = Decimal(maxData)
- if minData <= params <= maxData:
- return '%g' % params
- else:
- raise ServiceException(
- {'result': 2, 'description': u'%s参数超出可选范围,可取范围为%g-%g' % (desc, minData, maxData)})
- @staticmethod
- def reverse_hex(data):
- # type:(str) -> str
- if not isinstance(data, str):
- raise TypeError
- return "".join(list(reversed(re.findall(r".{2}", data))))
- @staticmethod
- def encode_str(data, length=2, ratio=1.0, base=16):
- # type:(any,int,float,int) -> str
- if not isinstance(data, Decimal):
- data = Decimal(data)
- if not isinstance(length, str):
- length = str(length)
- if not isinstance(ratio, Decimal):
- ratio = Decimal(ratio)
- end = 'X' if base == 16 else 'd'
- encodeStr = '%.' + length + end
- encodeStr = encodeStr % (data * ratio)
- return encodeStr
- @staticmethod
- def decode_str(data, ratio=1.0, base=16, reverse=False, to_int=True):
- '''
- ratio:比率单位转换
- '''
- if not isinstance(data, str):
- data = str(data)
- if reverse:
- data = "".join(list(reversed(re.findall(r".{2}", data))))
- if to_int:
- result = int(data, base) * ratio
- return int(result) if result == int(result) else round(result, 2)
- else:
- return '%.10g' % (int(data, base) * ratio)
- @staticmethod
- def decode_long_hex_to_list(data, split=2, ratio=1.0, base=16, transformer=True):
- # type:(str,int,float,int,bool) -> list
- '''
- return: list
- '''
- if len(data) % split != 0:
- raise Exception('Invalid data')
- pattern = r'.{%s}' % split
- hex_list = re.findall(pattern, data)
- if transformer:
- hex_list = map(lambda x: ChangyuanFive.decode_str(x, ratio=ratio, base=base), hex_list)
- return hex_list
- def test(self, coins):
- """
- 测试端口 测试机器启动 固定端口为 01
- {
- 'IMEI': '865650040606119',
- 'cmd': 210,
- 'data': '0303E8000001',
- 'funCode': 'D2'
- },
- """
- return self._start('coin', coins, 01)
- def get_dev_setting(self):
- """
- 获取设备参数
- :return:
- """
- result = self._send_data('D0', '00')
- data = result["data"]
- devSetting = self._parse_D0_data(data)
- disable = self.device.get('otherConf', {}).get('disableDevice')
- elecPrice = self.device.get("otherConf", {}).get("elecPrice", 0)
- needBindCard = self.device.get("otherConf", {}).get("needBindCard", True)
- vCardTime = self.device.get("otherConf", {}).get("vCardTime", 300)
- discount = self.device.get("otherConf", {}).get("discount", self.DEFAULT_DISCOUNT)
- onlineCardFee = self.device.get("otherConf", {}).get("onlineCardFee",0)
- maxTime = self.device.get("otherConf", {}).get("maxTime",720)
- devSetting.update(
- {'disable': disable, 'elecPrice': elecPrice, 'needBindCard': needBindCard, 'vCardTime': vCardTime, 'discount': discount,'onlineCardFee':onlineCardFee,'maxTime':maxTime})
- dev_control_cache = Device.get_dev_control_cache(self.device.devNo)
- devSetting['temperature'] = dev_control_cache.get('temperature', '获取中...')
- if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD:
- if devSetting['temperature'] == '获取中...':
- devSetting['temperature'] = self._get_dev_port_info().get('temperature')
- devSetting['voltage'] = dev_control_cache.get('voltage', '获取中...')
-
- return devSetting
- def set_device_function_param(self, request, lastSetConf):
- """设备设备的参数"""
- if "pwd" in request.POST:
- return self._set_password(request.POST["pwd"])
- if "old_pwd" in request.POST:
- old_pwd = request.POST["old_pwd"]
- new_pwd = request.POST["new_pwd"]
- cardType = request.POST["FaKacardType"]
- return self._set_send_card(old_pwd, new_pwd, cardType)
-
- # 卡券启动时间
- if 'vCardTime' in request.POST:
- vCardTime = int(request.POST.get('vCardTime'))
- if vCardTime != int(self.device['otherConf'].get('vCardTime', 300)):
- Device.get_collection().update_one({'devNo': self.device['devNo']}, {'$set': {'otherConf.vCardTime': vCardTime}})
- Device.invalid_device_cache(self.device.devNo)
-
- # 防止盗电的功能参数
- elecPrice = request.POST.get("elecPrice", 0)
- self._set_elec_price(elecPrice)
-
- # 折扣参数设置
- discount = request.POST.get("discount", 0)
- self._set_discount(discount)
-
- # 对一下参数的设置
- new_settings = dict()
- for _paramKey, _paramValue in lastSetConf.items():
- if request.POST.get(_paramKey) is not None:
- _paramValue = request.POST[_paramKey]
- new_settings[_paramKey] = _paramValue
- cardFree = "AA" if new_settings["cardFree"] else "00"
- new_settings.update({"cardFree": cardFree})
- self._set_all_settings(new_settings)
- maxTime = request.POST.get("maxTime")
- if maxTime is not None:
- self.set_max_time(int(maxTime))
- if "onlineCardFee" in request.POST:
- onlineCardFee = request.POST['onlineCardFee']
- self.device.update_device_obj(**{
- 'otherConf.onlineCardFee': onlineCardFee})
- def set_device_function(self, request, lastSetConf):
- """开关类参数配置"""
- if "disable" in request.POST:
- return self.set_dev_disable(request.POST.get('disable'))
- if "reboot" in request.POST:
- return self._reboot_device()
- if "cardFree" in request.POST:
- cardFree = "AA" if request.POST["cardFree"] else "00"
- lastSetConf.update({"cardFree": cardFree})
- return self._set_all_settings(lastSetConf)
-
- if "needBindCard" in request.POST:
-
- needBindCard = request.POST.get('needBindCard')
- otherConf = self.device.get("otherConf", dict())
- otherConf.update({"needBindCard": needBindCard})
- Device.objects.get(devNo=self.device.devNo).update(otherConf=otherConf)
- Device.invalid_device_cache(self.device.devNo)
-
- def get_port_status(self, force=False):
- '''
- 获取设备状态 昌原的状态都是被动获取的
- :param force:
- :return:
- '''
- statusDict = dict()
- if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD:
- portsInfo = self._get_dev_port_info().get('portInfo',{})
- allPorts = len(portsInfo)
- for portNum in range(allPorts):
- tempDict = portsInfo.get(str(portNum + 1), {})
- if 'status' in tempDict:
- statusDict[str(portNum + 1)] = {'status': tempDict.get('status')}
- elif 'isStart' in tempDict:
- if tempDict['isStart']:
- statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
- else:
- statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
- else:
- statusDict[str(portNum + 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})
- else:
- devCache = Device.get_dev_control_cache(self._device['devNo'])
- allPorts = devCache.get('allPorts', 10)
- for portNum in range(allPorts):
- tempDict = devCache.get(str(portNum + 1), {})
- if 'status' in tempDict:
- statusDict[str(portNum + 1)] = {'status': tempDict.get('status')}
- elif 'isStart' in tempDict:
- if tempDict['isStart']:
- statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
- else:
- statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
- else:
- statusDict[str(portNum + 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):
- return self.get_port_info(False)
- def get_port_info(self, port):
- '''
- 获取 端口的详细信息
- :param port:
- :return:
- '''
- # 昌源五代机新增在线卡功能,并修改了部分协议
- devCache = Device.get_dev_control_cache(self.device.devNo)
- if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD:
- portsInfo = self._get_dev_port_info()
- portInfo = portsInfo.get('portInfo',{}).get(port)
- if portInfo:
- portCache = devCache.get(port)
- startTime = portCache.get('startTime')
- needTime = portCache.get('needTime')
- leftTime = portInfo.pop('leftTime')
- usedTime = needTime - leftTime
- portInfo.update({"startTime": startTime, "usedTime": usedTime})
- temperature = portsInfo.get('temperature')
- devCache['temperature'] = temperature
- Device.update_dev_control_cache(self.device.devNo, devCache)
- return portInfo
- return devCache.get(str(port), dict())
- @property
- def isHaveStopEvent(self):
- return True
- def set_dev_disable(self, disable):
- if disable:
- status = '00AA'
- else:
- status = '0055'
- result = self._send_data(funCode='DD', data=status)
- if 'data' not in result or not ChangyuanFive._parse_COMMON_data(result.get('data')):
- raise ServiceException({'result': '2', 'description': u'设备停用错误,请联系厂商协助解决'})
- otherConf = self._device.get('otherConf', {})
- otherConf['disableDevice'] = disable
- Device.objects.filter(devNo=self._device['devNo']).update(otherConf=otherConf)
- Device.invalid_device_cache(self._device['devNo'])
- def stop(self, port=None):
- if not port:
- raise ServiceException({"result": "2", "description": u"请选择停止端口!"})
- self.stop_charging_port(port)
- def stop_charging_port(self, port):
- portHex = fill_2_hexByte(hex(int(port)), 2)
- result = self._send_data('D6', data=portHex)
- data = result.get('data')
- if data[6: 8] != '4F':
- raise ServiceException({'result': 2, 'description': u'停止充电失败,请重新试试'})
- # 这里只下发命令 不清理端口缓存,等上报事件清除
- # Device.clear_port_control_cache(self.device.devNo,int(port))
-
- def check_dev_status(self, attachParas = None):
- pass
-
- def start_device(self, package, openId, attachParas):
- chargeIndex = attachParas.get('chargeIndex')
- if not chargeIndex:
- raise ServiceException({'result': 2, 'description': u'请选择正确的充电端口'})
- coins = round(package.get('coins'), 2)
- price = round(package.get('price'), 2)
- rechargeRcdId = attachParas.get('linkedRechargeRecordId')
- orderNo = attachParas.get('orderNo')
- if self._vcard_id:
- vCardTime = self._device.get("otherConf", dict()).get("vCardTime", 300)
- result = self._start(payMoney='0', port=chargeIndex, time=vCardTime)
- result['finishedTime'] = int(time.time()) + vCardTime * 60 + 300
- else:
- discount = self.get_discount(rechargeRcdId)
- result = self._start(payMoney=coins, port=chargeIndex, discount=discount)
- result['finishedTime'] = int(time.time()) + 12 * 60 * 60
- lineInfo = Device.get_dev_control_cache(self.device.devNo).get(chargeIndex, {})
- is_continue = lineInfo.get('openId') == openId and lineInfo.get('status', Const.DEV_WORK_STATUS_IDLE) == Const.DEV_WORK_STATUS_WORKING
- portDict = {
- 'port': chargeIndex,
- 'openId': openId,
- 'isStart': True,
- 'coins': coins,
- 'price': price,
- 'orderNo': orderNo,
- "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'consumeType': 'mobile', # 用来显示的 显示在端口管理里面
- 'payType': '01',
- }
- if self._vcard_id:
- portDict['vCardId'] = self._vcard_id
- if rechargeRcdId:
- item = {
- 'rechargeRcdId': rechargeRcdId
- }
- if is_continue:
- pay_info = lineInfo.get('payInfo', list())
- else:
- pay_info = list()
- pay_info.append(item)
- portDict['payInfo'] = pay_info
- if is_continue:
- portDict['startTime'] = lineInfo.get('startTime', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
- if 'coins' in lineInfo:
- portDict['coins'] = coins + lineInfo['coins']
- if 'price' in lineInfo:
- portDict['price'] = price + lineInfo['price']
- Device.update_port_control_cache(self.device.devNo, portDict)
- return result
- def analyze_event_data(self, data):
- '''
- 解析事件
- :param data:
- :return:
- '''
- cmdCode = data[2:4]
- if cmdCode == 'D3':
- eventData = ChangyuanFive._parse_D3_data(data)
- elif cmdCode == 'D4':
- eventData = ChangyuanFive._parse_D4_data(data)
- elif cmdCode == 'D7':
- eventData = ChangyuanFive._parse_D7_data(data)
- elif cmdCode == 'D8':
- eventData = ChangyuanFive._parse_D8_data(data)
- elif cmdCode == 'D9':
- eventData = ChangyuanFive._parse_D9_data(data)
- elif cmdCode == 'DA':
- eventData = ChangyuanFive._parse_DA_data(data)
- if eventData['reasonCode']== "01":
- # 在线卡版本设备充满自停和插座掉落分离开
- if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD:
- reason = ChangyuanFive.FINISH_REASON_MAP.get("10", u'未知停止方式')
- # eventData['reasonCode'] == "10"
- # eventData['reason'] == reason
- eventData.update({'reasonCode' : "10"})
- eventData.update({'reason': reason})
- elif cmdCode == 'DE':
- eventData = ChangyuanFive._parse_DE_data(data)
- elif cmdCode == 'F0':
- eventData = ChangyuanFive._parse_F0_data(data)
- else:
- logger.error('error cmdCode <{}>, data is <{}>'.format(cmdCode, data))
- return
- eventData.update({'cmdCode': cmdCode})
- return eventData
- def get_device_function_by_key(self, data):
- if data == 'noRefund':
- res = self._no_refund_record()
- if not res:
- return {}
- return {'noRefund': res}
- def active_deactive_port(self, port, active):
- if not active:
- self.stop_charging_port(port)
- else:
- raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})
- def _check_package(self, package):
- """
- 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
- :param package:
- :return:
- """
- unit = package.get("unit", u"分钟")
- _time = float(package.get("time", 0))
- # 按时间计费
- if unit == u"小时":
- billingType = "time"
- _time = _time * 60
- elif unit == u"天":
- billingType = "time"
- _time = _time * 24 * 60
- elif unit == u"秒":
- billingType = "time"
- _time = _time / 60
- elif unit == u"分钟":
- billingType = "time"
- _time = _time
- else:
- billingType = "elec"
- _time = _time
- return _time, unit, billingType
- def get_discount(self, rechargeRcdId):
- """
- 根据启动方式的不通获取不同的折扣 金币启动的不打折 其余的根据设备的折扣而定
- """
- if rechargeRcdId:
- return self._device.get("otherConf", dict()).get("discount", self.DEFAULT_DISCOUNT)
- else:
- return self.DEFAULT_DISCOUNT
- def set_max_time(self, maxTime):
- data = "{:04X}".format(maxTime)
- try:
- self._send_data("F8", data, timeout=5)
- self.device.update_device_obj(**{
- 'otherConf.maxTime': maxTime})
- except ServiceException as e:
- raise ServiceException({"result": 2, "description": u"该设备暂不支持充电时长,请联系厂家进行升级"})
- def _set_discount(self, discount):
- Device.get_collection().update_one({'devNo': self.device['devNo']},
- {'$set': {'otherConf.discount': discount}})
- Device.invalid_device_cache(self.device.devNo)
- def _response_F0(self, cardType, cardNo, port,balance):
- cardType = str(cardType)
- cardNo = str(cardNo)
- port = str(port)
- oldBalance = self.encode_str(float(balance) * 100,6)
- onlineCardFee = 3 if self.device.otherConf.get('onlineCardFee',0) == 0 else self.device.otherConf.get('onlineCardFee')
- if RMB(balance) < RMB(onlineCardFee):
- money = self.encode_str(float(balance) * 100,4)
- else:
- onlineCardFee = float(onlineCardFee) * 100
- money = self.encode_str(onlineCardFee,4)
- data = cardType+cardNo+port+money+oldBalance
- result = self._send_data('F1',data)
- if result['data'][6:10] != '4F4B':
- raise ServiceException({'result': 2, 'description': u'支付失败'})
|