123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import logging
- import time
- from apilib.utils_datetime import timestamp_to_dt
- from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const
- 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
- logger = logging.getLogger(__name__)
- class FuncCode(object):
- # 发送设备事件
- GET_PORT_INFO = "01"
- START_DEV = "02"
- class HangXinBox(SmartBox):
- AUTO_STOP_COINS_MOTO = 250 # 摩托充满自停的金币数量
- AUTO_STOP_COINS_CAR = 1000 # 汽车充满自停的金币数量
- MIN_RECHARGE_MONEY = 20
- QUOTA_ELEC = 500
- WARNING_ELEC = 30
- SEND_DATA = "{funCode}{sendData}000000"
- PORT_MAP = {
- "1": "A1",
- "2": "A2",
- "3": "A3",
- "4": "A4",
- "5": "A5",
- "6": "A6",
- "7": "A7",
- "8": "A8",
- "9": "A9",
- "10": "A0",
- }
- PORT_STR_MAP = {v: k for k, v in PORT_MAP.items()}
- def __sendData(self, funCode, sendData = "0000", portStr = None, timeout = MQTT_TIMEOUT.NORMAL, orderNo = None):
- if portStr is None and funCode == FuncCode.GET_PORT_INFO:
- sendPort = "FA" # 全部的端口状态查询
- else:
- if not HangXinBox.PORT_MAP.has_key(portStr): raise ServiceException({'result': 2, 'description': u'无效的端口号'})
- sendPort = HangXinBox.PORT_MAP[portStr]
- data = self.SEND_DATA.format(funCode = funCode, sendData = sendData)
- result = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {"IMEI": self._device["devNo"], "funCode": sendPort, "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):
- portStr = HangXinBox.PORT_STR_MAP.get(data[: 2])
- statusBytes = data[2: 4]
- tempData = {
- "portStr": portStr,
- "statusBytes": statusBytes
- }
- elecNum = int(data[4: 8], 16)
- # 解析端口状态 若是存在剩余电量 添加入解析信息
- if statusBytes == "04":
- status = Const.DEV_WORK_STATUS_FAULT
- elif statusBytes == "07":
- if elecNum:
- status = Const.DEV_WORK_STATUS_WORKING
- tempData.update({"elecNum": str(elecNum)})
- else:
- status = Const.DEV_WORK_STATUS_IDLE
- else:
- status = None
- tempData.update({"status": status})
- return tempData
- def __get_one_port_info(self, port):
- result = self.__sendData(FuncCode.GET_PORT_INFO, portStr = port)
- return self.__parse_port_data(result.get("data"))
- def analyze_event_data(self, data):
- portStr = HangXinBox.PORT_STR_MAP.get(data[: 2])
- if not portStr:
- return
- elecNum = str(int(data[4: 8], 16))
- chargeStatus = data[8: 10]
- if chargeStatus == "01":
- desc = u"电量已经充满"
- elif chargeStatus == "02":
- desc = u"充电结束"
- elif chargeStatus == "03":
- desc = u"充电结束"
- else:
- desc = ""
- logger.error("undefined chargeStatus is %s" % chargeStatus)
- return {"leftElec": elecNum, "portStr": portStr, "chargeStatus": chargeStatus, "desc": 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 = str(port)
- # 获取启动设备的金币
- coins = int(package['coins'])
- hexCoins = fill_2_hexByte(hex(coins), 4)
- orderNo = attachParas.get('orderNo')
- # 启动设备 对于此协议如果此端口有负载则不会响应 mqtt超时
- result = self.__sendData(FuncCode.START_DEV, sendData = hexCoins, portStr = portStr,
- timeout = MQTT_TIMEOUT.START_DEVICE, orderNo = orderNo)
- tempStatus = self.__parse_port_data(result.get("data"))
- if not tempStatus.get("elecNum"):
- raise ServiceException({'result': 2, 'description': u"设备回应端口故障,请试试其他端口"})
- start_timestamp = int(time.time())
- result["finishedTime"] = start_timestamp + 3600 * 24
- portDict = {
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'finishedTime': result["finishedTime"],
- 'coins': float(coins),
- 'isStart': True,
- 'openId': openId,
- 'vCardId': self._vcard_id,
- "needElec": tempStatus.get("elecNum"),
- "startTime": timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S')
- }
- Device.update_dev_control_cache(self._device["devNo"], {str(port): portDict})
- return result
- def is_port_can_use(self, port, canAdd = False):
- port = str(int(port))
- portInfo = self.__get_one_port_info(port)
- if portInfo:
- status = portInfo.get("status", None)
- if status == Const.DEV_WORK_STATUS_IDLE:
- canUse = True
- desc = u""
- elif status == Const.DEV_WORK_STATUS_WORKING:
- canUse = False
- desc = u'该线路正在工作,暂时不能继续使用,请您使用其他线路,或者等待该线路工作完毕'
- elif status == Const.DEV_WORK_STATUS_FAULT:
- canUse = False
- desc = u'该线路故障,暂时不能使用,请您使用其他线路'
- elif status == Const.DEV_WORK_STATUS_FORBIDDEN:
- canUse = False
- desc = u'该线路已被禁用,暂时不能使用,请您使用其他线路'
- else:
- canUse = False
- desc = u'该线路未知状态,暂时不能使用'
- else:
- canUse = False
- desc = u"未知充电端口,无法使用"
- return canUse, desc
- def get_port_info(self, line = None):
- tempStatus = self.__get_one_port_info(line)
- elec = tempStatus.get("elecNum")
- portInfo = Device.get_dev_control_cache(self._device["devNo"]).get(str(line))
- if not portInfo:
- logger.error("no port info")
- raise ServiceException({'result': 2, 'description': u'暂无端口信息,请稍后再试'})
- coins = portInfo.get("coins")
- if not coins:
- logger.error("port info has no coins info")
- # 类型判断是汽车还是摩托车 两种车的类型不同 对应的充满自停的费用不同
- if int(coins) == HangXinBox.AUTO_STOP_COINS_MOTO:
- data = {"consumeMoney": u"%s币" % str(HangXinBox.AUTO_STOP_COINS_MOTO - int(elec))}
- elif int(coins) == HangXinBox.AUTO_STOP_COINS_CAR:
- data = {"consumeMoney": u"%s币" % str(HangXinBox.AUTO_STOP_COINS_CAR - int(elec))}
- else:
- data = {"leftMoney": u"%s币" % elec}
- data.update({"leftElec": elec})
- return data
- def set_device_function_param(self, request, lastSetConf):
- minRechargeMoney = request.POST.get("minRechargeMoney")
- quotaElec = request.POST.get("quotaElec")
- warningElec = request.POST.get("warningElec")
- if quotaElec < warningElec:
- raise ServiceException({"result": 2, "description": u"设置失败,请确认您的电量余额是否已经小于报警电量"})
- if minRechargeMoney:
- lastSetConf.update({"minRechargeMoney": minRechargeMoney})
- if quotaElec:
- lastSetConf.update({"quotaElec": quotaElec})
- if warningElec:
- lastSetConf.update({"warningElec": warningElec})
- Device.objects.filter(devNo = self._device["devNo"]).update(otherConf = lastSetConf)
- Device.invalid_device_cache(self._device["devNo"])
- def get_dev_setting(self):
- dev = Device.objects.get(devNo = self._device["devNo"])
- otherConf = dev.otherConf
- return {
- "minRechargeMoney": otherConf.get("minRechargeMoney", self.MIN_RECHARGE_MONEY),
- "quotaElec": otherConf.get("quotaElec", self.QUOTA_ELEC),
- "warningElec": otherConf.get("warningElec", self.WARNING_ELEC)
- }
- @property
- def show_pay_unit(self):
- return u"金币"
|