123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import copy
- import datetime
- import logging
- import random
- import time
- from typing import TYPE_CHECKING
- from apps.web.constant import Const
- from apps.web.core.adapter.base import SmartBox, start_error_timer
- from apps.web.core.device_define.baolai import send_request
- from apps.web.core.exceptions import ServiceException
- from apps.web.device.models import Device
- from apps.web.user.models import MyUser, ConsumeRecord
- if TYPE_CHECKING:
- pass
- logger = logging.getLogger(__name__)
- class ChargingGatewayPlugBox(SmartBox):
- """
- """
- def __init__(self, device):
- super(ChargingGatewayPlugBox, self).__init__(device)
- devObj = self.device.my_obj
- self.nodeDict = devObj.nodeDict
- self.billingType = devObj.otherConf.get('billingType', 1) # 0 :电量 1:时间 2:功率
- self.config_list = devObj.otherConf.get('config_list', [])
- self.onceCard = devObj.otherConf.get('onceCard', 100)
- self.cardTime = devObj.otherConf.get('cardTime', 180)
- self.cardElec = devObj.otherConf.get('cardElec', 1)
- self.node_index = None
- for nodeIndex, nodeDevNo in devObj.nodeDict.items():
- if nodeDevNo == device['devNo']:
- self.node_index = int(nodeIndex)
- break
- else:
- continue
-
- self.gatewayDevNo = Device.get_collection().find({'devNo':devObj.devNo})[0]['gateImei']
-
- @property
- def isHaveStopEvent(self):
- return True
- def translate_funcode(self, funCode):
- funCodeDict = {
- }
- return funCodeDict.get(funCode, '')
- def translate_event_cmdcode(self, cmdCode):
- cmdDict = {
- }
- return cmdDict.get(cmdCode, '')
- def get_port_from_ab(self, portAB):
- portConf = {'A': 0, 'B': 1, 'C': 2}
- if portAB in portConf:
- return portConf[portAB]
- return portAB
- def get_abport_from_index(self, port):
- portConf = {'0': 'A', '1': 'B', '2': 'C'}
- return portConf.get(port)
- def send_request(self, cmdPath, jsonPara,cmdKind=2):
- return send_request(self.device.devNo, self.gatewayDevNo, cmdPath, jsonPara,cmdKind)
- def test(self, coins, port=1):
- return self.send_request('device/plug/list', {})
- @start_error_timer(missMessages=[u"请您选择合适的充电线路、电池类型信息", u"请您选择合适的充电线路", u"该端口正在使用中"])
- def start_device(self, package, openId, attachParas):
- if attachParas is None:
- raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
- if not attachParas.has_key('chargeIndex'):
- raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
- port = int(self.get_port_from_ab(attachParas['chargeIndex']))
- attachParas['chargeIndex'] = port
- unit = package.get('unit', u'分钟')
- needTime, needElec = None, None
- jsonPara = {'node_index': self.node_index, 'port_index': port, 'switch_state': 1}
- cmdPath = 'cmd/write-node'
- if self.billingType == 1:
- if unit == u'秒':
- if int(package['time']) < 60:
- raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
- needTime = int(float(package['time']) / 60.0)
- jsonPara.update({'charge_time': needTime, 'charge_mode': 1, 'charge_energy': 0})
- elif unit == u'分钟':
- needTime = int(float(package['time']))
- jsonPara.update({'charge_time': needTime, 'charge_mode': 1, 'charge_energy': 0})
- elif unit == u'小时':
- needTime = int(float(package['time']) * 60)
- jsonPara.update({'charge_time': needTime, 'charge_mode': 1, 'charge_energy': 0})
- elif unit == u'天':
- needTime = int(float(package['time']) * 60 * 24)
- jsonPara.update({'charge_time': needTime, 'charge_mode': 1, 'charge_energy': 0})
- else:
- raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的套餐,请运营商配置正确的套餐'})
- elif self.billingType == 0:
- if unit == u'度':
- needElec = int(float(package['time']) * 1000) # 微度
- jsonPara.update({'charge_energy': needElec, 'charge_mode': 0, 'charge_time': 0})
- else:
- raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的套餐,请运营商配置正确的套餐'})
- else:
- if not self.config_list:
- raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的分档功率,请运营商配置正确的分档功率'})
- cmdPath = 'cmd/write-node-with-power'
- coins = int(float(package['coins']) * 100) # 单位为分
- jsonPara.update({'power': {'money': coins, 'config_list': self.config_list}})
- devInfo = self.send_request(cmdPath, jsonPara)
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- if devInfo['rst'] == 0: # 成功
- newValue = {
- str(port): {
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
- }
- else: # TODO result的枚举列出原因
- raise ServiceException({'result': 2, 'description': u'充电插座响应异常,请您稍后再试哦'})
- servicedInfo = {}
- if self.billingType == 1:
- finishedTime = int(time.time()) + needTime * 60
- devInfo['needTime'] = needTime
- servicedInfo = {'needTime': needTime, 'billingType': 'time'}
- elif self.billingType == 0:
- finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
- devInfo['needElec'] = float(package['time'])
- servicedInfo = {'needElec': float(package['time']), 'billingType': 'elec'}
- else:
- finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
- servicedInfo = {'billingType': 'power'}
- newValue[str(port)].update({'power':10}) # 端口下的数据依赖心跳上报,但是心跳有时间间隔,这样查看服务的时候,因为功率是0,会认为已经结束,这里给一个初始值
- newValue.update({'finishedTime': finishedTime})
-
- Device.clear_port_control_cache(self._device['devNo'], port)
- Device.update_dev_control_cache(self._device['devNo'], newValue)
- devInfo['finished_time'] = finishedTime
- devInfo['sequanceNo'] = devInfo['data']['data']['transaction_id']
- devInfo['servicedInfo'] = servicedInfo
-
- return devInfo
- # 获取设备配置参数
- def get_dev_setting(self):
- if not self.node_index:
- raise ServiceException({'result': 2, 'description': u'读取失败!请您先把插座本身作为子节点添加进来,选择扫码增加子节点,然后扫码添加即可'})
-
- devInfo = self.send_request('cmd/get-node-config', {'node_index': self.node_index},3)
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- config = devInfo['data']['data']
- billDict = {'0': 'elec', '1': 'time', '2': 'power'}
- config.update({
- 'chargeType': billDict.get(str(self.billingType)),
- 'once_card': self.onceCard*0.01,
- 'time': self.cardTime,
- 'elec': self.cardElec,
- 'config_list': self.config_list,
- 'charge_full_timeout':config['charge_full_time_threshold'],
- 'no_load_timeout':config['no_load_time_threshold'],
- })
- return config
- # 设置设备配置参数
- def set_dev_setting(self, setConf):
- setConf.update({'node_index': self.node_index})
- devObj = Device.objects.get(devNo=self._device['devNo'])
- billDict = {'elec': 0, 'time': 1, 'power': 2}
- devObj.otherConf.update({
- 'billingType': billDict.get(setConf['chargeType']),
- 'onceCard': int(float(setConf['once_card'])*100),
- 'cardTime': int(setConf['time']),
- 'cardElec': int(setConf['elec']),
- 'config_list': setConf['config_list'],
- })
- devObj.save()
- setConf.pop('chargeType')
- setConf.pop('once_card')
- setConf.pop('time')
- setConf.pop('elec')
- setConf.pop('config_list')
-
- setConf.update({
- 'charge_full_time_threshold':int(setConf['charge_full_timeout']),
- 'no_load_time_threshold':int(setConf['no_load_timeout'])
- })
- setConf.pop('charge_full_timeout')
- setConf.pop('no_load_timeout')
-
- devInfo = self.send_request('cmd/set-node-config', setConf,3)
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- return devInfo
- def get_port_status_from_dev(self):
- # 先到设备上,把所有子节点的信息取出来,记录到主节点的缓存
- devInfo = self.send_request('cmd/get-status', {'node_index': self.node_index})
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- allPorts, usedPorts = 0, 0
- result = {}
- for portInfo in devInfo['data']['data']['port_list']:
- portId = str(portInfo['index'])
- portDict = {
- 'status': self.__translate_status_from_str(str(portInfo['charge_status'])),
- 'watt': portInfo['power'],
- 'ampr': portInfo['current'] * 0.001,
- 'voltage': portInfo['voltage'],
- 'elec': portInfo['energy_consumed'] * 0.001,
- 'usedTime': portInfo['time_consumed'],
- 'duration': portInfo['time_consumed']
- }
- sequanceNo = portInfo['transaction_id']
- if sequanceNo:
- try:
- rcd = ConsumeRecord.objects.get(sequanceNo=sequanceNo)
- portDict['openId'] = rcd['openId']
- portDict['coins'] = float(str(rcd['coin'])) # 都用coins
- portDict['money'] = float(str(rcd['money']))
- portDict['sequanceNo'] = sequanceNo
- if u'虚拟卡' in rcd.remarks:
- portDict['consumeType'] = 'mobile_vcard'
- elif u'刷卡' in rcd.remarks:
- portDict['consumeType'] = 'card'
- portDict['cardNo'] = rcd.servicedInfo.get('cardNo')
- else:
- portDict['consumeType'] = 'mobile'
- portDict['billingType'] = 'power'
- if rcd.servicedInfo['billingType'] == 'time':
- portDict['billingType'] = 'time'
- portDict['needTime'] = rcd.servicedInfo['needTime']
- portDict['leftTime'] = rcd.servicedInfo['needTime'] - portInfo['time_consumed'] or 0
- if rcd.servicedInfo['billingType'] == 'elec':
- portDict['billingType'] = 'elec'
- portDict['needElec'] = rcd.servicedInfo['needElec']
- user = MyUser.objects(openId=portDict['openId']).first()
- if user:
- portDict['nickName'] = user.nickname
- except Exception, e: # IC卡,如果没有绑定,不会有consumeRcd,应该直接从订单中拿数据
- pass
- result[portId] = portDict
- if portInfo['charge_status'] == 1:
- usedPorts += 1
- allPorts += 1
- result.update({'usedPorts': usedPorts, 'allPorts': allPorts, 'usePorts': allPorts - usedPorts})
- Device.update_dev_control_cache(self._device['devNo'], result)
- return result
- def get_port_info(self, line):
- line = self.get_port_from_ab(line)
- portCache = Device.get_dev_control_cache(self.device.devNo)
- return portCache.get(str(line), {})
- def __translate_status_from_str(self, status):
- dictConf = {
- '0': Const.DEV_WORK_STATUS_IDLE,
- '1': Const.DEV_WORK_STATUS_WORKING,
- '2': Const.DEV_WORK_STATUS_IDLE,
- '3': Const.DEV_WORK_STATUS_IDLE,
- }
- return dictConf.get(status, Const.DEV_WORK_STATUS_FAULT)
- def get_port_status(self, force=False):
- if force:
- self.get_port_status_from_dev()
- portCache = Device.get_dev_control_cache(self._device['devNo'])
- result = {}
- for ii in range(5):
- if str(ii) in portCache:
- if ii == 0:
- result['A'] = portCache[str(ii)]
- elif ii == 1:
- result['B'] = portCache[str(ii)]
- elif ii == 2:
- result['C'] = portCache[str(ii)]
- return result
- def lock_unlock_port(self, port, lock=True):
- port = self.get_port_from_ab(port)
- portInfo = self.get_port_info(port)
- if portInfo['status'] == Const.DEV_WORK_STATUS_WORKING:
- 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 stop_charging_port(self, port):
- port = self.get_port_from_ab(port)
- portInfo = self.get_port_info(port)
- if portInfo.get('billingType', None) == 'power':
- devInfo = self.send_request('cmd/write-node-with-power',
- {'node_index': self.node_index, 'port_index': port, 'switch_state': 0,
- 'power': {'money': 0,
- 'config_list': [{'power': 200, 'price': 100, 'time': 240}]}})
- else:
- devInfo = self.send_request('cmd/write-node',
- {'node_index': self.node_index, 'port_index': port, 'switch_state': 0,
- 'charge_mode': 0, 'charge_time': 0, 'charge_energy': 0})
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- if devInfo['rst'] == 0:
- Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
- return True if devInfo['rst'] == 0 else False
- def add_to_gateway(self, gatewayDevNo):
- self.add_node(self._device['devNo'])
-
- def remove_from_gateway(self, gatewayDevNo):
- self.remove_node(self._device['devNo'])
- # 如果
- # 柏来有两条刷卡事件,一个是查询余额,对应的是余额播报回复;一个是开始充电事件,对应的是启动设备充电
- def response_card_start(self, portIndex, orderNo):
- jsonParas = {'node_index': self.node_index, 'port_index': portIndex, 'transaction_id': orderNo,
- 'switch_state': 1, 'charge_type': self.billingType}
- if self.billingType == 0: # 按电量
- jsonParas.update({'charge_type': 2})
- jsonParas.update({'charge_energy': self.onceCard * 0.01 * self.cardElec * 1000})
- elif self.billingType == 1: # 按时间
- jsonParas.update({'charge_type': 1})
- jsonParas.update({'charge_time': self.onceCard * 0.01 * self.cardTime})
- else: # 按功率
- jsonParas.update(
- {'charge_type': 3, 'charge_power': {'money': self.onceCard, 'config_list': self.config_list}})
- devInfo = self.send_request('cmd/control-nfc-charge', jsonParas)
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- return devInfo
- def active_deactive_port(self, port, active):
- port = self.get_port_from_ab(port)
- if active:
- raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
- return self.stop_charging_port(port)
- def set_device_function_param(self, request, lastSetConf):
- newConf = copy.deepcopy(request.POST)
- newConf.pop('logicalCode', None)
- self.set_dev_setting(newConf)
- def response_card_balance(self, cardNo, nodeIndex, portIndex, balance):
- devInfo = self.send_request('cmd/write-card-query-response',
- {
- 'node_index': nodeIndex,
- 'port_index': portIndex,
- 'card_no': cardNo,
- 'balance': int(float(balance * 100)),
- 'timeout': 10
- })
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- return devInfo
-
- def get_node(self, node):
- nodeInfo = {
- 'signal':node.signal,
- 'rssi':node.get('rssi',39),
- 'online':node.online,
- }
- if 'suid' in node:
- nodeInfo.update({
- 'devNo':node['suid'],
- 'suid':node['suid'],
- })
- if 'devNo' in node:
- nodeInfo.update({
- 'devNo':node['devNo'],
- 'suid':node['devNo'],
- })
- return nodeInfo
-
- def get_dev_online_status(self):
- devInfo = self.send_request('device/gateway/detail', {})
- return devInfo['data']['plug_gateway']['is_online']
- def update_dev_info(self):
- devInfo = self.send_request('device/gateway/update',
- {'province': '', 'city': '', 'county': '',
- 'address': '', 'longitude': 0.0, 'latitude': 0.0})
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- def add_node(self, nodeDevNo):
- # 首先检查子节点是否已经注册了
- devObj = Device.objects.filter(devNo = nodeDevNo).first()
- if devObj is None:
- raise ServiceException({'result': 2, 'description': u'请先扫码注册子设备插座,然后再加入网关'})
- # 检查是否绑定在其他主节点,如果绑定了其他主节点,必须提示
- if devObj.gatewayNode and devObj.gatewayNode != self._device['devNo']:
- raise ServiceException({'result': 2, 'description': u'该子节点已经绑定在其他主节点下,请先解绑后,再重新添加'})
-
- nodeList = self.get_node_list()
- # 首先检查是否已经添加进来了
- exist = devObj.gatewayNode == self._device['devNo']
- sendList = [{'node_index': node['node_index'], 'plug_id': node['suid']} for node in nodeList]
-
- if exist: # 如果已经存在了,直接下发就Ok
- pass
- else:
- nodeIndexList = [node['node_index'] for node in nodeList]
- ii = 1
- for ii in range(1, 50):
- if ii not in nodeIndexList:
- break
- else:
- continue
- sendList.append({'node_index': ii, 'plug_id': nodeDevNo})
-
- devInfo = self.send_request('cmd/build-network',
- {'channel': random.randint(1, 8),
- 'plug_list': sendList, 'timeout': 15})
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- # 主节点内容更新
- devObj = Device.objects.get(devNo = self._device['devNo'])
- for sendInfo in sendList:
- devObj.nodeDict.update({str(sendInfo['node_index']):sendInfo['plug_id']})
- devObj.save()
- # 子节点的也要更新
- devObj = Device.objects.get(devNo = nodeDevNo)
- devObj.gatewayNode = self._device['devNo']
- devObj.save()
- def remove_node(self, nodeDevNo):
- nodeList = self.get_node_list()
- sendList = []
- index = -1
- nodeDict = {}
- for node in nodeList:
- if node['suid'] != nodeDevNo:
- sendList.append({'node_index': node['node_index'], 'plug_id': node['suid']})
- nodeDict[str(node['node_index'])] = node['suid']
- else:
- index = node['node_index']
- if index == -1:
- return
- devInfo = self.send_request('cmd/build-network',
- {'channel': random.randint(1, 8),
- 'plug_list': sendList, 'timeout': 5})
- if devInfo['data']['code'] != 0:
- raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
- # 主节点更新
- try:
- devObj = Device.objects.get(devNo = self._device['devNo'])
- devObj.nodeDict = nodeDict
- devObj.save()
- except Exception, e:
- pass
- # 子节点更新
- try:
- devObj = Device.objects.get(devNo = nodeDevNo)
- devObj.gatewayNode = ''
- devObj.save()
- except Exception, e:
- return
-
- # 如果是一体板的,需要把端口删除掉
- if nodeDevNo == self._device['devNo']:
- Device.invalid_device_control_cache(nodeDevNo)
-
- def get_signal(self):
- result = {'rst':0}
- devInfo = Device.get_dev(self._device['devNo'])
- if devInfo['online']:
- result.update({'signal':devInfo['signal']})
- return result
- else:
- return {'signal':0,'rst':0}
- def get_node_list(self):
- result = []
- for index,nodeDevNo in self.nodeDict.items():
- nodeDevInfo = Device.get_dev(nodeDevNo)
- nodeInfo = self.get_node(nodeDevInfo)
- nodeInfo.update({'node_index':int(index)})
- result.append(nodeInfo)
- return result
-
- def get_node_devNo(self, nodeIndex):
- return self.nodeDict.get(str(nodeIndex))
-
|