1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import json
- import logging
- import re
- import threading
- from decimal import Decimal
- from typing import TYPE_CHECKING, Optional
- from apilib.utils_datetime import to_datetime
- from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT
- from apps.web.core.adapter.base import SmartBox
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.device.models import Device, Group
- from apps.web.user.models import ConsumeRecord, MyUser, Card
- logger = logging.getLogger(__name__)
- if TYPE_CHECKING:
- pass
- # from apps.web.device.models import Device, Group
- # from apps.web.user.models import ConsumeRecord, MyUser, Card
- class CmdHelper(object):
-
- def __init__(self):
- pass
-
- @staticmethod
- def encode_str(data, length=2, ratio=1.0, base=16):
- # type:(str,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, base=16, to_num=True):
- # type:(str,Optional[float, int],int, bool) -> Optional[float, str]
- """
- ratio:比率单位转换
- """
- if not isinstance(data, str):
- data = str(data)
- if to_num:
- return int(data, base) * ratio
- else:
- return '%.10g' % (int(data, base) * ratio)
-
- @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 split_data_to_list(split_str, data):
- # type:(str,str) ->Optional[list, None]
- """
- return: list
- """
- part = '({})'
- all_ = sum(map(lambda _: int(_) * 2, split_str))
- pattern = reduce(lambda a, b: a + b, map(lambda _: part.format('..' * int(_)), split_str))
- result = re.match(pattern, data[:all_])
- if result:
- return result.groups()
-
- @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)})
-
- def _port_info_01(self, encode=None, decode=None):
- """
- 查询端口状态
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data')
- port = self.decode_str(data[10:12])
- status = self.decode_str(data[12:14])
- left_value = self.decode_str(data[14:18])
- power = round(self.decode_str(data[18:22], ratio=0.1), 2)
-
- return {'port': port, 'status': status, 'left_value': left_value, 'power': power, }
-
- else:
- port = encode['port']
- cmd = '01'
- port = self.encode_str(port)
- return {'funCode': 52, 'data': cmd + port}
-
- def _start_port_02(self, encode=None, decode=None):
- """
- 开启端口
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data')
- port = self.decode_str(data[2:4], )
- status = self.decode_str(data[4:6], )
- power = self.decode_str(data[6:10], ratio=0.1, )
- return {'port': port, 'status': status, 'power': power, }
-
- else:
- port, start_type, value = encode['port'], encode['start_type'], encode['value']
- cmd = '02'
- port = self.encode_str(port)
- start_type = self.encode_str(start_type)
- value = self.encode_str(value, length=4)
- return {'funCode': '5202', 'data': cmd + port + start_type + value}
-
- def _port_stop_03(self, encode=None, decode=None):
- """
- 停止端口
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data')
- port = self.decode_str(data[10:12], )
- status = self.decode_str(data[12:14], )
- used_elec = self.decode_str(data[14:18], ratio=0.01) # 度
- left_value = self.decode_str(data[18:22])
- power = self.decode_str(data[22:26], ratio=0.1) # 瓦
- return {'port': port, 'status': status, 'used_elec': used_elec, 'left_value': left_value, 'power': power}
-
- else:
- port = encode['port']
- cmd = '03'
- port = self.encode_str(port)
- return {'funCode': 52, 'data': cmd + port}
-
- def _get_gear_param_04(self, decode=None):
- """
- 读取分档
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- all_data = self.split_data_to_list('2121212121', data[10:])
- power1 = self.decode_str(all_data[0])
- power1ratio = self.decode_str(all_data[1])
- power2 = self.decode_str(all_data[2])
- power2ratio = self.decode_str(all_data[3])
- power3 = self.decode_str(all_data[4])
- power3ratio = self.decode_str(all_data[5])
- power4 = self.decode_str(all_data[6])
- power4ratio = self.decode_str(all_data[7])
- power5 = self.decode_str(all_data[8])
- power5ratio = self.decode_str(all_data[9])
- return {
- 'power1': power1, 'power1ratio': power1ratio,
- 'power2': power2, 'power2ratio': power2ratio,
- 'power3': power3, 'power3ratio': power3ratio,
- 'power4': power4, 'power4ratio': power4ratio,
- 'power5': power5, 'power5ratio': power5ratio,
- }
-
- else:
- cmd = '04'
- return {'funCode': 52, 'data': cmd}
-
- def _set_gear_param_05(self, encode=None, decode=None):
- """
- 设置分档
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data')
- status = self.decode_str(data[10:12], )
- return {'status': status}
- else:
- kw = encode.get('gear_param')
- cmd = '05'
- data = ''
- data += self.encode_str(kw.get('power1'), length=4)
- data += self.encode_str(kw.get('power1ratio', ))
- data += self.encode_str(kw.get('power2'), length=4)
- data += self.encode_str(kw.get('power2ratio', ))
- data += self.encode_str(kw.get('power3'), length=4)
- data += self.encode_str(kw.get('power3ratio', ))
- data += self.encode_str(kw.get('power4'), length=4)
- data += self.encode_str(kw.get('power4ratio', ))
- data += self.encode_str(kw.get('power5'), length=4)
- data += self.encode_str(kw.get('power5ratio', ))
- return {'funCode': 52, 'data': cmd + data}
-
- def _get_dev_param_06(self, decode=None):
- """
- 读取设备参数
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- all_data = self.split_data_to_list('22222111111122111114111', data[10:])
- port_max_power = self.decode_str(all_data[0])
- dev_max_power = self.decode_str(all_data[1])
- coin_quote = self.decode_str(all_data[2])
- card_quote = self.decode_str(all_data[3])
- free_time = self.decode_str(all_data[4])
- remove_load_time = self.decode_str(all_data[5])
- noload_wait_time = self.decode_str(all_data[6])
- free_mode_en = self.decode_str(all_data[7])
- refund_mode_en = self.decode_str(all_data[8])
- full_stop_en = self.decode_str(all_data[9])
- coin_en = self.decode_str(all_data[10])
- card_en = self.decode_str(all_data[11])
- float_power = self.decode_str(all_data[12])
- float_time = self.decode_str(all_data[13])
- onec_card_fee = self.decode_str(all_data[14])
- volume = self.decode_str(all_data[15])
- consumeModule = self.decode_str(all_data[16])
- temp_max_limit = self.decode_str(all_data[17])
- smork_max_limit = self.decode_str(all_data[18])
- password = self.decode_str(all_data[19])
- power_report_interval = self.decode_str(all_data[20])
- smork_temp_report_interval = self.decode_str(all_data[21])
- port_status_interval = self.decode_str(all_data[22])
-
- return {
- 'port_max_power': port_max_power,
- 'dev_max_power': dev_max_power,
- 'coin_quote': coin_quote,
- 'card_quote': card_quote,
- 'free_time': free_time,
- 'remove_load_time': remove_load_time,
- 'noload_wait_time': noload_wait_time,
- 'free_mode_en': free_mode_en,
- 'refund_mode_en': refund_mode_en,
- 'full_stop_en': full_stop_en,
- 'coin_en': coin_en,
- 'card_en': card_en,
- 'float_power': float_power,
- 'float_time': float_time,
- 'onec_card_fee': onec_card_fee,
- 'volume': volume,
- 'consumeModule': consumeModule,
- 'temp_max_limit': temp_max_limit,
- 'smork_max_limit': smork_max_limit,
- 'password': password,
- 'power_report_interval': power_report_interval,
- 'smork_temp_report_interval': smork_temp_report_interval,
- 'port_status_interval': port_status_interval,
- }
-
- else:
- cmd = '06'
- return {'funCode': 52, 'data': cmd}
-
- def _set_dev_param_07(self, encode=None, decode=None):
- """
- 设置设备参数
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- status = self.decode_str(data[10:12])
- return {'status': status}
-
- else:
- kw = encode.get('dev_param')
- cmd = '07'
- data = ''
- data += self.encode_str(kw.get('port_max_power'), length=4)
- data += self.encode_str(kw.get('dev_max_power'), length=4)
- data += self.encode_str(kw.get('coin_quote'), length=4)
- data += self.encode_str(kw.get('card_quote'), length=4)
- data += self.encode_str(kw.get('free_time'), length=4)
- data += self.encode_str(kw.get('remove_load_time'))
- data += self.encode_str(kw.get('noload_wait_time'))
- data += self.encode_str(kw.get('free_mode_en'))
- data += self.encode_str(kw.get('refund_mode_en'))
- data += self.encode_str(kw.get('full_stop_en'))
- data += self.encode_str(kw.get('coin_en'))
- data += self.encode_str(kw.get('card_en'))
- data += self.encode_str(kw.get('float_power'), length=4)
- data += self.encode_str(kw.get('float_time'), length=4)
- data += self.encode_str(kw.get('onec_card_fee'))
- data += self.encode_str(kw.get('volume'))
- data += self.encode_str(kw.get('consumeModule'))
- data += self.encode_str(kw.get('temp_max_limit'))
- data += self.encode_str(kw.get('smork_max_limit'))
- data += self.encode_str(kw.get('password'), length=8)
- data += self.encode_str(kw.get('power_report_interval'))
- data += self.encode_str(kw.get('smork_temp_report_interval'))
- data += self.encode_str(kw.get('port_status_interval'))
- return {'funCode': 52, 'data': cmd + data}
-
- def _get_card_param_08(self, decode=None):
- """
- 读取读卡参数
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- cardPassword = self.decode_str(data[10:22])
- sector = self.decode_str(data[22:24])
- return {'cardPassword': cardPassword, 'sector': sector}
-
- else:
- cmd = '08'
- return {'funCode': 52, 'data': cmd}
-
- def _set_card_param_09(self, encode=None, decode=None):
- """
- 设置读卡参数
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- status = self.decode_str(data[10:12])
- return {'status': status}
-
- else:
- kw = encode.get('card_param')
- cmd = '09'
- data = ''
- data += self.encode_str(kw.get('cardPassword'), length=12)
- data += self.encode_str(kw.get('sector'))
- return {'funCode': 52, 'data': cmd + data}
-
- def _set_port_enable_0A(self, encode=None, decode=None):
- """
- 设置端口禁用/启用
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- status = self.decode_str(data[10:12])
- return {'status': status}
-
- else:
- port, enable = encode['port'], encode['enable']
- cmd = '0A'
- data = ''
- data += self.encode_str(port)
- if enable == True:
- data += '01'
- else:
- data += '00'
- return {'funCode': 52, 'data': cmd + data}
-
- def _set_dev_power_status_0B(self, encode=None, decode=None):
- """
- 设置设备电源状态 开机/待机
- :param encode:
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- status = self.decode_str(data[10:12])
- return {'status': status}
-
- else:
- power_on = encode['power_on']
- cmd = '0B'
- data = ''
- if power_on == True:
- data += '01'
- else:
- data += '00'
- return {'funCode': 52, 'data': cmd + data}
-
- def _get_dev_consume_total_0C(self, decode=None):
- """
- 获取设备投币/刷卡总量
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- coin_total = round(self.decode_str(data[10:14]))
- card_total = round(self.decode_str(data[14:18], ratio=0.1), 1)
- return {'coin_total': coin_total, 'card_total': card_total}
-
- else:
- cmd = '0C'
- return {'funCode': 52, 'data': cmd}
-
- def _set_dev_fualt_recovery_0D(self, decode=None):
- """
- 设备故障状态清除 未做
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- status = self.decode_str(data[2:4])
- return {'status': status}
-
- else:
- cmd = '0D'
- return {'funCode': 52, 'data': cmd}
-
- def _get_dev_version_0E(self, decode=None):
- """
- 获取设备版本信息
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- data = data[8:]
- hw_ver_len = int(data[2:4], 16)
- hw_ver = data[4: 4 + hw_ver_len * 2]
- soft_ver_len = int(data[4 + hw_ver_len * 2: 6 + hw_ver_len * 2], 16)
- soft_ver = data[6 + hw_ver_len * 2: 6 + soft_ver_len * 2]
- return {'hw_ver': hw_ver, 'soft_ver': soft_ver}
-
- else:
- cmd = '0E'
- return {'funCode': 52, 'data': cmd}
-
- def _get_dev_all_status_0F(self, decode=None):
- """
- 获取设备全部状态
- :param decode:
- :return:
- """
- if decode:
- data = decode.get('data', '')
- powers = map(lambda _: self.decode_str(_, ratio=1.0), self.split_data_to_list('2' * 10, data[10:50]))
- left_values = map(lambda _: self.decode_str(_), self.split_data_to_list('2' * 10, data[50:90]))
-
- result = {}
- for i in xrange(len(powers)):
- result['{}'.format(i + 1)] = {
- 'port': i + 1,
- 'power': powers[i],
- 'left_value': left_values[i],
- 'status': Const.DEV_WORK_STATUS_IDLE if left_values[i] == 0 and powers[
- i] == 0 else Const.DEV_WORK_STATUS_WORKING
- }
- return result
-
- else:
- cmd = '0F'
- return {'funCode': 52, 'data': cmd}
- class GaoBoRuiChargingBox(SmartBox, CmdHelper):
- def __init__(self, device):
- super(GaoBoRuiChargingBox, self).__init__(device)
- self.ctrInfo = Device.get_dev_control_cache(device.devNo)
- self.consumeMode = self.device['otherConf'].get('consumeMode')
-
- def check_dev_status(self, attachParas=None):
- if attachParas is None:
- raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
-
- if not attachParas.has_key('chargeIndex'):
- raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
-
- port = attachParas['chargeIndex']
- openId = attachParas['openId']
- result = self.send_mqtt(data={'funCode': '88', 'data': port})
- if 'uid' in result:
- if openId != result['uid']:
- raise ServiceException({'result': 2, 'description': u'当前端口繁忙'})
-
- def get_dev_info(self):
- return self._get_dev_version_0E(decode=self.send_mqtt(self._get_dev_version_0E()))
-
- def test(self, coins):
- raise NotImplementedError(u'设备未实现 `test`')
-
- def start_device(self, package, openId, attachParas):
- raise NotImplementedError('cannot call `start_device` of base class SmartBox')
-
- def start(self, packageId, openId=None, attachParas=None):
- if not attachParas:
- attachParas = {}
- washConfig = self.device.get('washConfig', dict())
- package = washConfig.get(packageId)
- if not package:
- raise ServiceException({'result': 2, 'description': u'未找到套餐,请联系经销商!'}) # new
- return self.start_device(package, openId, attachParas)
-
- def stop(self, port=None):
- encode = {'port': port}
- return self._port_stop_03(decode=self.send_mqtt(self._port_stop_03(encode=encode)))
-
- def calc_stop_back_coins(self, totalFee, remainderTime, totalTime):
- refundFee = round(totalFee * (float(remainderTime) / totalTime), 2)
- if refundFee > totalFee:
- refundFee = totalFee
-
- if refundFee <= 0.0:
- refundFee = 0.00
-
- return refundFee
-
- def stop_charging_port(self, port):
- return self.send_mqtt({'port': int(port), 'funCode': 'stopPort'})
-
- # 访问设备,获取设备信息
- def getDevInfo(self):
- pass
-
- def analyze_event_data(self, data):
- cmdCode = data[2:4]
-
- if cmdCode == '53' or cmdCode == '4C':
- subCmd = data[8:10]
- result = {'cmdCode': cmdCode, 'subCmd': subCmd}
-
- if subCmd == '36': # 在线卡请求余额
- result['session'] = data[6:8]
- result['card_no'] = data[10:18]
- result['fee'] = data[18:20]
-
-
- elif subCmd == '35': # 离线卡上报开始
- result['session'] = data[6:8]
- result['port'] = int(data[10:12], 16)
- result['card_no'] = data[12:20]
- result['fee'] = round(int(data[20:22], 16) * 0.1)
- result['balance'] = round(int(data[22:26], 16) * 0.1) # 元
- if data[26:28] == '01':
- result['billingType'] = 'time'
- result['needTime'] = int(data[28:32], 16)
- else:
- result['billingType'] = 'elec'
- result['needElec'] = round(int(data[28:32], 16) * 0.01, 2)
-
- result['power'] = round(int(data[32:36], 16) * 0.1, 2)
-
-
- elif subCmd == '3B':
- result['port'] = int(data[10:12], 16)
- result['card_no'] = data[12:20]
- result['fee'] = round(int(data[20:22], 16) * 0.1, 2)
- result['balance'] = round(int(data[22:26], 16) * 0.1, 2)
-
-
- elif subCmd == '32':
- upload = data[10:-2]
- points = re.findall('..' * 3, upload)
- powers = {}
- for item in points:
- port = self.decode_str(item[:2], to_num=False)
- power = int(self.decode_str(item[2:], ratio=0.1))
- powers[port] = power
-
- result['powers'] = powers
-
-
- elif subCmd == '3E':
- result = {}
-
- decode = {'data': data[10:60]}
- gear_params = self._get_gear_param_04(decode=decode)
- result.update(gear_params)
-
- decode = {'data': data[60:]}
- dev_params = self._get_dev_param_06(decode=decode)
- result.update(dev_params)
- return result
-
-
- elif subCmd == '3F':
- FAULT_CODE = {
- '1': '键盘故障',
- '2': '显示器故障',
- '3': '刷卡板故障',
- '4': '子网故障',
- '5': '存储故障',
- '6': '过温故障',
- '7': '烟雾故障',
- '8': '漏电',
- '9': '短路',
- 'A': '过压',
- 'B': '欠压',
- 'C': '整机过流',
- 'D': '恶意操作',
- 'E': '继电器粘连',
- 'F': '其它故障',
- }
- errCode = data[12:14][-1]
- statusInfo = FAULT_CODE.get(errCode)
- if errCode == '6': # 过温(1 字节)
- temp = int(data[14:16], 16)
- statusInfo = statusInfo + '(过温,当前{}度)'.format(temp)
- result.update({'statusInfo': statusInfo, 'FaultCode': errCode,
- 'uart': data})
- elif errCode == 'A': # 过压(2 字节)
- overVoltage = int(data[14:16], 16)
- statusInfo = statusInfo + '(过压,当前{}V)'.format(overVoltage)
- result.update({'statusInfo': statusInfo,
- 'FaultCode': errCode,
- 'uart': data})
- elif errCode == 'B': # 欠压(1 字节)
- overVoltage = int(data[14:16], 16)
- statusInfo = statusInfo + '(欠压,当前{}V)'.format(overVoltage)
- result.update({'statusInfo': statusInfo,
- 'FaultCode': errCode,
- 'uart': data})
- elif errCode == 'C': # 过流(2 字节)
- overCurrent = int(data[14:16], 16)
- statusInfo = statusInfo + '(过流,当前{}A)'.format(overCurrent)
- result.update({'statusInfo': statusInfo, 'cmdCode': cmdCode,
- 'FaultCode': errCode,
- 'uart': data})
-
- else: # 通道号(1字节)
- port = int(data[14:16], 16)
- if 0 < port < 11:
- result.update({'statusInfo': statusInfo, 'cmdCode': cmdCode, 'FaultCode': errCode,
- 'uart': data})
- else:
- result.update({'statusInfo': statusInfo, 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode,
- 'uart': data})
-
-
- return result
-
- def active_deactive_port(self, port, active):
- if active == False:
- self.stop_charging_port(port)
-
- def lock_unlock_port(self, port, lock=True):
- encode = {'port': port, 'enable': not lock}
- result = self._set_port_enable_0A(decode=self.send_mqtt(self._set_port_enable_0A(encode=encode)))
- if result.get('status') == 1:
- pass
- else:
- raise ServiceException({'result': 2, 'description': '设备端口( {} ) {}失败'.format(port, '禁用' if lock else '启用')})
-
- # 端口是否可用,如果canAdd为True,表示可以追加钱
- def is_port_can_use(self, port, canAdd=False):
- port = str(port)
- try:
- portDict = self.get_port_status()
- except ServiceException, e:
- return False, e.result.get('description')
- except Exception, e:
- logger.error('error = %s' % e)
- return False, u'获取端口状态失败'
-
- if port in portDict:
- if portDict[port]['status'] == Const.DEV_WORK_STATUS_IDLE:
- return True, ''
- elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FAULT:
- return False, u'该线路故障,暂时不能使用,请您使用其他线路'
- elif portDict[port]['status'] == Const.DEV_WORK_STATUS_WORKING:
- if canAdd:
- return True, ''
- return False, u'该线路正在工作,暂时不能继续使用,请您使用其他线路,或者等待该线路工作完毕'
- elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
- return False, u'该线路已被禁止使用,请您使用其他线路'
- elif portDict[port]['status'] == Const.DEV_WORK_STATUS_CONNECTED:
- return True, u''
- else:
- return False, u'线路未知状态,暂时不能使用'
-
- return False, u'未知端口,无法使用'
- def get_port_status(self, force=False):
- if force:
- self._get_dev_all_status_0F(decode=self.send_mqtt(self._get_dev_all_status_0F()))
-
- result = {}
- for k,v in self.ctrInfo.items():
- if k.isdigit():
- result[k] = v
-
- return result
-
- def dealer_get_port_status(self):
- """
- 远程上分的时候获取端口状态
- :return:
- """
- return self.get_port_status()
-
- def get_dev_setting(self):
-
- result = {}
- params = self._get_dev_param_06(decode=self.send_mqtt(self._get_dev_param_06()))
- result.update(params)
- gear_params = self._get_gear_param_04(decode=self.send_mqtt(self._get_gear_param_04()))
- result.update(gear_params)
- card_params = self._get_card_param_08(decode=self.send_mqtt(self._get_card_param_08()))
- result.update(card_params)
- consumeTotal = self._get_dev_consume_total_0C(decode=self.send_mqtt(self._get_dev_consume_total_0C()))
- result.update(consumeTotal)
- devVersion = self._get_dev_version_0E(decode=self.send_mqtt(self._get_dev_version_0E()))
- result.update(devVersion)
-
- disableDevice = self.device['otherConf'].get('disableDevice', False)
- result.update({'disableDevice': disableDevice})
- refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
- result.update({'refundProtectionTime': refundProtectionTime})
-
- return result
-
- def set_device_function(self, request, lastSetConf):
- if 'disable' in request.POST:
- result = self._set_dev_param_07(decode=self.send_mqtt(self._set_dev_param_07()))
- if result.get('status') == 1:
- pass
- else:
- raise ServiceException({'result': 2, 'description': '设备设置失败'})
-
- def set_device_function_param(self, request, lastSetConf):
-
- def check_update(name_list):
- updata_dict = {}
- update = False
- for _ in name_list:
- if request.POST.get(_) != lastSetConf.get(_):
- update = True
- updata_dict[_] = request.POST.get(_)
- else:
- updata_dict[_] = lastSetConf.get(_)
- return update, updata_dict
-
- gear_param_name = ['power1', 'power1ratio', 'power2', 'power2ratio', 'power3', 'power3ratio', 'power4',
- 'power4ratio', 'power5', 'power5ratio', ]
-
- update, gear_param = check_update(gear_param_name)
- if update:
- encode = {'gear_param': gear_param}
- result = self._set_gear_param_05(decode=self.send_mqtt(self._set_gear_param_05(encode=encode)))
- if result.get('status') == 1:
- pass
- else:
- raise ServiceException({'result': 2, 'description': '设备分档参数设置失败'})
-
- card_param_name = ['cardPassword', 'sector', ]
- update, gear_param = check_update(card_param_name)
- if update:
- encode = {'card_param': gear_param}
- result = self._set_card_param_09(decode=self.send_mqtt(self._set_card_param_09(encode=encode)))
- if result.get('status') == 1:
- pass
- else:
- raise ServiceException({'result': 2, 'description': '卡参数设置失败'})
-
- dev_param_name = ['port_max_power', 'dev_max_power', 'coin_quote', 'card_quote', 'free_time',
- 'remove_load_time', 'noload_wait_time', 'free_mode_en', 'refund_mode_en', 'full_stop_en',
- 'coin_en', 'card_en', 'float_power', 'float_time', 'onec_card_fee', 'volume', 'consumeModule',
- 'temp_max_limit', 'smork_max_limit', 'password', 'power_report_interval',
- 'smork_temp_report_interval', 'port_status_interval', ]
- update, dev_param = check_update(dev_param_name)
- if update:
- encode = {'dev_param': dev_param}
- result = self._set_dev_param_07(decode=self.send_mqtt(self._set_dev_param_07(encode=encode)))
- if result.get('status') == 1:
- pass
- else:
- raise ServiceException({'result': 2, 'description': '设备设备参数设置失败'})
-
- if 'disableDevice' in request.POST:
- disableDevice = self.device['otherConf'].get('disableDevice', False)
- if disableDevice == request.POST['disableDevice']:
- pass
- else:
- disableDevice = request.POST['disableDevice']
- self.set_dev_disable(disableDevice)
-
- if 'refundProtectionTime' in request.POST:
- refundProtectionTime = self.device['otherConf'].get('refundProtectionTime', False)
- if refundProtectionTime == request.POST['refundProtectionTime']:
- pass
- else:
- refundProtectionTime = request.POST['refundProtectionTime']
- Device.get_collection().update_one({'devNo': self._device['devNo']}, {
- '$set': {'otherConf.refundProtectionTime': refundProtectionTime}})
- Device.invalid_device_cache(self.device.devNo)
- def set_dev_disable(self, disable):
- """
- 设备端锁定解锁设备
- :param disable:
- :return:
- """
- if disable:
- encode = {'power_on': False}
- else:
- encode = {'power_on': True}
- result = self._set_dev_power_status_0B(decode=self.send_mqtt(self._set_dev_power_status_0B(encode=encode)))
- if result.get('status') == 1:
- Device.get_collection().update_one({'devNo': self._device['devNo']}, {
- '$set': {'otherConf.disableDevice': disable}})
- Device.invalid_device_cache(self.device.devNo)
- else:
- raise ServiceException({'result': 2, 'description': '设备待机/开机设置失败'})
-
- def get_port_static_info(self, portDict):
- allPorts, usedPorts = 0, 0
- for k, v in portDict.items():
- if k.isdigit():
- allPorts += 1
- if ('isStart' in v and v['isStart']) or ('status' in v and v['status'] != Const.DEV_WORK_STATUS_IDLE):
- usedPorts += 1
-
- return allPorts, usedPorts, allPorts - usedPorts
-
- def get_port_status_from_dev(self):
- data = self._get_dev_all_status_0F()
- result = self.send_mqtt(data)
- result = self._get_dev_all_status_0F(decode=result)
-
- for strPort, info in result.items():
- if strPort in self.ctrInfo:
- self.ctrInfo[strPort].update({'status': info['status']})
- else:
- self.ctrInfo[strPort] = info
- allPorts, usedPorts, usePorts = self.get_port_static_info(self.ctrInfo)
- self.ctrInfo.update({'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
-
- Device.update_dev_control_cache(self._device['devNo'], self.ctrInfo)
-
- return result
-
- def get_port_info(self, port):
- encode = {'port': port}
- result = self._port_info_01(decode=self.send_mqtt(self._port_info_01(encode=encode)))
- return result
-
- def async_update_portinfo_from_dev(self):
- class Sender(threading.Thread):
- def __init__(self, smartBox):
- super(Sender, self).__init__()
- self._smartBox = smartBox
-
- def run(self):
- try:
- self._smartBox.get_port_status_from_dev()
- except Exception as e:
- logger.info('get port stats from dev,e=%s' % e)
-
- sender = Sender(self)
- sender.start()
-
- def get_port_using_detail(self, port, ctrInfo, isLazy=False):
- """
- 获取设备端口的详细信息
- :param port:
- :param ctrInfo:
- :return:
- """
- detailDict = ctrInfo.get(str(port), {})
-
- try:
- portInfo = self.get_port_info(str(port))
-
- # 有的主机报的信息leftTime错误
- if portInfo.has_key('leftTime') and portInfo['leftTime'] < 0:
- portInfo.pop('leftTime')
-
- detailDict.update(portInfo)
- except Exception, e:
- logger.exception('get port info from dev=%s err=%s' % (self.device.devNo, e))
- return detailDict
-
- portData = {}
- startTimeStr = detailDict.get('startTime', None)
- if startTimeStr is not None and 'usedTime' not in detailDict:
- startTime = to_datetime(startTimeStr)
- usedTime = int(round((datetime.datetime.now() - startTime).total_seconds() / 60.0))
- portData['usedTime'] = usedTime
- elif detailDict.get('usedTime'):
- usedTime = detailDict.get('usedTime')
- portData['usedTime'] = usedTime
- else:
- usedTime = None
-
- if 'cType' in detailDict:
- if detailDict['cType'] == 1:
- detailDict['leftTime'] = detailDict.get('left_value')
- else:
- detailDict['leftElec'] = round(detailDict.get('left_value') * 0.01, 2)
-
- if detailDict.has_key('leftTime') and (usedTime > 0):
- if detailDict['leftTime'] == 65535:
- portData['leftTime'] = 65535
- detailDict['usedTime'] = 0
- detailDict['actualNeedTime'] = 0
- else:
- portData['actualNeedTime'] = int(detailDict['leftTime']) + int(usedTime)
- if detailDict.has_key('needTime') and portData['actualNeedTime'] > detailDict['needTime']:
- portData['actualNeedTime'] = detailDict['needTime']
-
- portData['leftTime'] = detailDict['leftTime']
- if detailDict.has_key('coins'):
- if self.device.is_auto_refund:
- portData['leftMoney'] = round(
- float(detailDict['coins']) * int(detailDict['leftTime']) / (
- int(detailDict['leftTime']) + int(usedTime)), 2)
- portData['consumeMoney'] = round(
- float(detailDict['coins']) * int(portData['usedTime']) / (
- int(detailDict['leftTime']) + usedTime), 2)
- elif detailDict.has_key('leftTime'):
- portData['leftTime'] = detailDict['leftTime']
-
- if (not detailDict.has_key('leftTime')) and (usedTime is not None):
- if detailDict.has_key('needTime'):
- portData['leftTime'] = detailDict['needTime'] - usedTime
-
- if detailDict.has_key('coins') and float(detailDict['coins']) != 0: # 只有支持退费的设备才显示可退费数据
- if self.device.is_auto_refund:
- portData['leftMoney'] = round(
- float(detailDict['coins']) * portData['leftTime'] / detailDict['needTime'], 2)
- portData['consumeMoney'] = round(
- float(detailDict['coins']) * portData['usedTime'] / detailDict['needTime'], 2)
-
- if detailDict.has_key('openId'):
- user = MyUser.objects(openId=detailDict['openId']).first()
- if user:
- portData['nickName'] = user.nickname
-
- if detailDict.has_key('cardId'):
- if not detailDict.has_key('consumeType'):
- portData['consumeType'] = 'card'
- card = Card.objects.get(id=detailDict['cardId'])
- if card.cardName:
- portData['cardName'] = card.cardName
- portData['cardNo'] = card.cardNo
- # 注意,如果是IC卡,不支持余额回收,这里也不要显示出来
- if card.cardType == 'IC' and portData.has_key('leftMoney'):
- portData.pop('leftMoney')
-
- elif detailDict.has_key('openId') and (not detailDict.has_key('consumeType')):
- if detailDict.get('vCardId'):
- portData['consumeType'] = 'mobile_vcard'
- else:
- portData['consumeType'] = 'mobile'
- elif detailDict.has_key('consumeType') and detailDict['consumeType'] == 'coin':
- portData['consumeType'] = 'coin' # 硬币的都无法退费
- if portData.has_key('leftMoney'):
- portData.pop('leftMoney')
-
- # 做个特殊处理
- if portData.has_key('needTime'):
- if portData['needTime'] == '999' or portData['needTime'] == '充满自停':
- portData['needTime'] = u'充满自停'
- else:
- portData['needTime'] = u'%s分钟' % portData['needTime']
-
- # 如果剩余时间为65535,表示未接插头
- if portData.has_key('leftTime') and portData['leftTime'] == 65535:
- portData['leftTime'] = u'(线路空载)'
- portData['usedTime'] = 0
- portData['needTime'] = 0
-
- detailDict.update(portData)
-
- for k, v in detailDict.items():
- if v < 0:
- detailDict.pop(k)
-
- # 因为前台显示的开始时间如果带年,就显示不下,这里做个切割
- if detailDict.has_key('startTime') and detailDict['startTime'].count('-') == 2:
- detailDict['startTime'] = to_datetime(detailDict['startTime']).strftime('%m-%d %H:%M:%S')
-
- return detailDict
-
- @property
- def isHaveStopEvent(self):
- return True
-
- def get_many_port_info(self, portList):
- return None
-
- def start_device_realiable(self, order):
- # type:(ConsumeRecord)->dict
-
- if order.orderNo[:10] == self.device.ownerId[-10:]: # 此时为远程上分 先停一次
- self.stop_charging_port(order.used_port)
-
- attachParas = order.attachParas
- package = order.package
-
- unit = package.get('unit')
- if unit == '分钟':
- cType = 1
- cValue = int(package.get('time'))
-
- elif unit == '度':
- cType = 2
- cValue = int(package.get('time') * 100)
- else:
- raise ServiceException({'result': 2, 'description': '设备单位配置错误'})
-
- port = int(attachParas['chargeIndex'])
-
- data = {
- 'funCode': 'startPort',
- 'port': port,
- 'cType': cType, # 1 按时间 2 按电量
- 'cValue': cValue,
- 'order_id': order.orderNo,
- 'uid': order.openId
- }
-
- # 订单中记录一份下发收到源数据
- uart_source = []
- uart_source.append(
- {'write_start': json.dumps(data, indent=4), 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
-
- result = MessageSender.send(device=self.device,
- cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
- payload=data,
- timeout=120)
- if result['rst'] == 9:
- raise ServiceException({'result': 2, 'description': '启动失败,当前端口已被其他人使用'})
-
- uart_source.append(
- {'rece_start': json.dumps(result, indent=4), 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
-
- order.update(uart_source=uart_source)
-
- return result
-
- def calc_elec_fee(self, spend_elec):
- group = Group.objects.get(id=self.device['groupId'])
- return float(group.otherConf.get('elecFee', 0)) * spend_elec
-
- @property
- def support_monthly_package(self):
- return False
-
- def stop_by_order(self, port, orderNo):
- return self.stop_charging_port(port)
- def isHaveFaultHandle(self):
- return True
- def faultHandle(self, **kw):
- self._set_dev_fualt_recovery_0D(decode=self.send_mqtt(self._set_dev_fualt_recovery_0D(), timeout=5))
- def send_mqtt(self, data=None, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=MQTT_TIMEOUT.NORMAL):
- """
- 发送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, timeout=timeout)
- 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})
- elif result['rst'] == 8:
- 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
|