123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import time
- from apilib.utils_datetime import timestamp_to_dt
- from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT
- from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, hexbyte_2_bin
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.device.models import Device
- class DataType(object):
- # 发送设备事件
- GET_PORT_INFO = '02'
- GET_DEV_SETTING = '01'
- START_DEV = '51'
- STOP_DEV = '63'
- class DeKangBox(SmartBox):
- DATA = '{port}{dataType}{data}00'
- def __sendData(self, data, FunCode='A4',timeout = MQTT_TIMEOUT.NORMAL,orderNo=None):
- result = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {'IMEI': self._device['devNo'], 'funCode': FunCode, 'data': data},
- timeout = timeout)
- if result.has_key('rst') and 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
- @staticmethod
- def __parse_port_data(data):
- """
- 状态:
- 00 : 未插 空闲 AA5524019B010000000008CA000000 00 000000000000000000000000000000000000000000B409BB
- 11 : 插上 检测负载 AA5524019B010000000008CA000000 11 0000000000000000000000000000000000000000002AD9BB
- 12 : 付款 继电器连接 AA5524019B01000000000000043B3B 12 1400000000000000000000000000000000000000003401BB
- 13 : 付款 继电器断开 AA5524019B010000000025D404330B 13 1400000000000000000000000000000000000000005529BB
- 52 : 启动 使用 AA5524019B01000000000000043B3A 52 14000000000000000000000000000000000000000065B1BB
- :param data:
- :return:
- """
- portStr = str(int(data[: 2], 16))
- power = str(int(data[2: 6], 16) / 10.0)
- ampere = str(int(data[6: 10], 16) / 1000.0)
- rightTime = str(int(data[14: 16], 16) * 3600 + int(data[16: 18], 16) * 60 + int(data[18: 20], 16))
- portStatus = hexbyte_2_bin(data[20: 22]) # 设备状态是一个字节 解析成bit进行判断
- curConsume = str(int(data[22: 24], 16))
- canPay = bool(int(portStatus[3: 4]))
- statusBin = portStatus[4:]
- leftTime = (int(rightTime) + 59 )/ 60
- if statusBin == "0000": # 待机转改
- status = Const.DEV_WORK_STATUS_IDLE
-
- elif statusBin == "0001": # 负载接入状态
- status = Const.DEV_WORK_STATUS_CONNECTED
-
- elif statusBin == "0010": # 充电正常运行状态
- status = Const.DEV_WORK_STATUS_WORKING
-
- elif statusBin == "0011": # 负载断开状态
- status = Const.DEV_WORK_STATUS_WORKING
-
- elif statusBin == "0100": # 充电完成负载未断开
- status = Const.DEV_WORK_STATUS_FINISHED
-
- else:
- status = Const.DEV_WORK_STATUS_FAULT
-
- return {
- portStr: {
- 'power': power,
- 'ampere': ampere,
- 'rightTime': rightTime,
- 'canPay': canPay,
- 'status': status,
- 'curConsume': curConsume,
- 'portStatus': statusBin,
- 'leftTime': leftTime,
- 'port': portStr
- }
- }
- def __get_one_port_info_from_dev(self, port):
- portStr = fill_2_hexByte(hex(int(port)), num=2)
- sendData = self.DATA.format(port=portStr, dataType=DataType.GET_PORT_INFO, data=fill_2_hexByte(hex(0), 16))
- result = self.__sendData(sendData)
- data = result['data'][10: -6]
- tempStatus = self.__parse_port_data(data)
- data = tempStatus.popitem()[1]
- data.update({'portStr': portStr})
- return data
-
- def analyze_event_data(self, data):
- """
- 目前只有状态改变才会有上报事件 上报数据为状态改变的通道当前状态
- """
- tempStatus = self.__parse_port_data(data[10: -6])
-
- analyzeData = {}
- for k, v in tempStatus.items():
- v.update({'portStr': k})
- analyzeData = v
- return analyzeData
-
- def check_dev_status(self, attachParas = None):
- if not isinstance(attachParas, dict):
- raise ServiceException({'result': 2, 'description': u'请选择合适的充电桩'})
- port = attachParas.get('chargeIndex', None)
- if not port:
- raise ServiceException({'result': 2, 'description': u'请选择合适的充电桩'})
- # 校验端口状态
- canPay, desc = self.is_port_can_use(port)
- if not canPay:
- raise ServiceException({'result': 2, 'description': desc})
-
- def start_device(self, package, openId, attachParas):
- if not isinstance(attachParas, dict):
- raise ServiceException({'result': 2, 'description': u'请选择合适的充电桩'})
- port = attachParas.get('chargeIndex', None)
- if not port:
- raise ServiceException({'result': 2, 'description': u'请选择合适的充电桩'})
- portStr = fill_2_hexByte(hex(int(port)), 2)
-
- # 校验远程上分
- onPoints = attachParas.get('onPoints')
- if onPoints:
- # 校验端口状态
- canPay, desc = self.is_port_can_use(port)
- if not canPay:
- raise ServiceException({'result': 2, 'description': desc})
- # 获取启动设备的金币
- coins = float(package['coins'])
- price = float(package['price'])
- hexCoins = fill_2_hexByte(hex(int(coins * 10)), 4)
- finishedTime = int(time.time()) + 3600 * 12
-
- orderNo = attachParas.get('orderNo')
- # 启动设备
- sendData = self.DATA.format(port=portStr, dataType=DataType.START_DEV, data=hexCoins+hexCoins+fill_2_hexByte(hex(0), 8))
- result = self.__sendData(sendData,timeout=MQTT_TIMEOUT.START_DEVICE,orderNo=orderNo)
-
- # 缓存服务信息
- start_timestamp = int(time.time())
- result['finishedTime'] = finishedTime
- portDict = {
- 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'),
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'finishedTime': result['finishedTime'],
- 'coins': coins,
- 'price': price,
- 'isStart': True,
- 'openId': openId,
- 'vCardId': self._vcard_id,
- 'orderNo': orderNo
- }
-
- if 'linkedRechargeRecordId' in attachParas and attachParas.get('isQuickPay', False):
- pay_info = []
- item = {
- 'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])
- }
- pay_info.append(item)
- portDict['payInfo'] = pay_info
-
- Device.update_dev_control_cache(self._device['devNo'], {str(port): portDict})
- return result
-
- def stop(self, port=None):
- """
- 停止事件中 返还的数据会有存在对于该端口的剩余时间和剩余的金额 对其进行退款
- """
- if port is None: return
- portStr = fill_2_hexByte(hex(int(port)), 2)
- sendData = self.DATA.format(port=portStr, dataType=DataType.STOP_DEV, data=fill_2_hexByte(hex(0), 16))
- return self.__sendData(sendData)
- def get_port_status_from_dev(self):
- sendData = self.DATA.format(port='00', dataType=DataType.GET_PORT_INFO, data=fill_2_hexByte(hex(0), 16))
- result = self.__sendData(sendData)
- data = result['data'][10: -6]
- portInfo = dict()
- while data:
- tempStatus = self.__parse_port_data(data)
- portInfo.update(tempStatus)
- data = data[64:]
- allPorts, usedPorts, usePorts = self.get_port_static_info(portInfo)
- Device.update_dev_control_cache(self._device['devNo'], {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- for port, info in portInfo.items():
- if ctrInfo.has_key(port):
- lineInfo = ctrInfo[port]
- if 'openId' in lineInfo and lineInfo.get('isStart') and info['status'] == Const.DEV_WORK_STATUS_IDLE:
- ctrInfo[port] = info
- else:
- ctrInfo[port].update({'status': info['status']})
- ctrInfo[port].update({'portStatus': info['portStatus']})
- else:
- ctrInfo[port] = info
-
- Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
- return portInfo
-
- def get_port_status(self, force = False):
- """
- 从缓存中获取状态,若是缓存中没有获取到设备状态,直接从设备获取后再从缓存获取
- 然后从设备的信息中提取出端口状态 最后再次更新设备端口缓存 并返还提取的端口状态
- :param force:
- """
- if force:
- return self.get_port_status_from_dev()
- curInfo = Device.get_dev_control_cache(self._device['devNo'])
- if not curInfo.has_key('allPorts'):
- self.get_port_status_from_dev()
- curInfo = Device.get_dev_control_cache(self._device['devNo'])
- allPorts = curInfo.get('allPorts')
- statusDict = dict()
- portStr = lambda x:str(x+1)
- for port in xrange(allPorts):
- tempDict = curInfo.get(portStr(port), {})
- if tempDict.has_key('status'):
- tempStatus = {'status': tempDict.get('status')}
- elif tempDict.has_key('isStart'):
- if tempDict.get('isStart'):
- tempStatus = {'status': Const.DEV_WORK_STATUS_WORKING}
- else:
- tempStatus = {'status': Const.DEV_WORK_STATUS_IDLE}
- else:
- tempStatus = {'status': Const.DEV_WORK_STATUS_IDLE}
- statusDict.setdefault(portStr(port), tempStatus)
- 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 is_port_can_use(self, port, canAdd=False):
- portInfo = self.__get_one_port_info_from_dev(port)
- canPay = portInfo.get('canPay')
-
- desc = '' if canPay else u'请检查充电插座是否连接成功'
- return canPay, desc
- def get_port_info(self, line=None):
- portHex = fill_2_hexByte(hex(int(line)), 2)
- sendData = self.DATA.format(port=portHex, dataType=DataType.GET_PORT_INFO, data=fill_2_hexByte(hex(0), 16))
- result = self.__sendData(sendData)
- tempStatus = self.__parse_port_data(result.get('data')[10: -6]).get(str(line))
- leftTime = int(round(int(tempStatus.get('rightTime')) / 60.0, 0))
- power = tempStatus.get('power')
- ampere = tempStatus.get('ampere')
- return {'port': str(line), 'leftTime': leftTime, 'power': power, 'ampere':ampere}
- def get_dev_setting(self):
- sendData = self.DATA.format(port='00', dataType=DataType.GET_DEV_SETTING, data=fill_2_hexByte(hex(0), 16))
- result = self.__sendData(sendData)
- data = result['data'][10: -6]
- maxPayment = str(int(data[2: 4], 16)) # 单通道单次最大付款数(角)
- unitChargeTime = str(int(data[6: 8], 16) * 6) # 单位金额充电时间(1元充电时间) 分钟 倍率是6 也就是说解析出来的数据*6才是真正的时间 单位分钟
- maxPower = str(int(data[32: 34], 16) * 10) # 设备最大功率(w)
- coinsNum = str(int(data[50: 54], 16)) # 投币数量
- version = 'V'+str(round(int(data[54: 56], 16) * 0.1, 1)) # 软件版本
- totalCardConsume = str(int(data[56: 64], 16) / 10.0) # 刷卡总数(获取数据角,显示元)
- result = {
- 'maxPayment': maxPayment,
- 'unitChargeTime': unitChargeTime,
- 'maxPower': maxPower,
- 'coinsNum': coinsNum,
- 'version': version,
- 'totalCardConsume': totalCardConsume
- }
- return result
- def active_deactive_port(self, port, active):
- if not active:
- self.stop(port)
- def isHaveStopEvent(self):
- return True
|