# encoding=utf-8 import logging import datetime from apilib.monetary import RMB from apps.web.constant import DeviceCmdCode from apps.web.core.adapter.base import SmartBox, MQTT_TIMEOUT from apps.web.core.device_define.huopo import HuopoCacheMgr, DefaultParams, Caculater from apps.web.core.exceptions import ServiceException from apps.web.core.networking import MessageSender from apps.web.user.models import MyUser from apps.web.device.models import Group, Device from taskmanager.mediator import task_caller logger = logging.getLogger(__name__) class HuoPoBox(SmartBox): def __init__(self, device): super(HuoPoBox, self).__init__(device) def _send_data(self, funCode, data, cmd=DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC, timeout=MQTT_TIMEOUT.NORMAL): result = MessageSender.send( device=self.device, cmd=cmd, payload={ "IMEI": self.device.devNo, "data": data, "funCode": funCode }, timeout=timeout ) if "rst" in result 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 def _open(self): otherConf = self.device.get("otherConf", dict()) snNum = otherConf.get("snNum") try: snNum = int(snNum or "") except ValueError: raise ServiceException({"result": "", "description": u"道闸编号设置错误"}) data = DefaultParams.INSTRUCT_FORMAT.format( snNum=snNum, dutou=DefaultParams.DUTOU_NUM, auth=DefaultParams.AUTH_NUM, stay=DefaultParams.STAY_NUM ) return self._send_data("", data) def _get_card_wait(self): """ 获取设备侧的参数 :return: """ result = self._send_data("GC", "", cmd=DeviceCmdCode.OPERATE_DEV_SYNC) return int(result.get("data")[:2], 16) def _set_card_wait(self, waitTime): if not self.device.driverVersion < "v2.0.0": data = "{:0>2X}".format(waitTime) self._send_data("CC", data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC) def _get_server_config(self): """ 获取设备侧的参数 :return: """ otherConf = self.device.get("otherConf", dict()) parkInfo = self.get_parkingInfo() return { "maxParking": otherConf.get("maxParking", DefaultParams.DEFAULT_MAX_PARKING), "VIPMaxParking": otherConf.get("VIPMaxParking", DefaultParams.DEFAULT_VIP_MAX_PARKING), "snNum": otherConf.get("snNum", DefaultParams.DEFAULT_SN_NUM), "freeTime": otherConf.get("freeTime", DefaultParams.DEFAULT_FREE_TIME), "maxConsume": otherConf.get("maxConsume", DefaultParams.DEFAULT_FREE_TIME), "parkingNum": parkInfo.get("maxParking", 0), "VIPParkingNum": parkInfo.get("VIPMaxParking", 0) } def _get_device_config(self): """ 获取服务器侧参数 :return: """ if self.device.driverVersion < "v2.0.0": return { "cardWait": u"驱动版本过低,暂不支持" } return { "cardWait": self._get_card_wait() # 刷卡等待时间 } def calculate_consume(self, duration, package): """计算在给定的小时内要扣除的数量""" maxConsume = self.device.get("otherConf", dict()).get("maxConsume", DefaultParams.DEFAULT_MAX_CONSUME) freeTime = self.device.get("otherConf", dict()).get("freeTime", DefaultParams.DEFAULT_FREE_TIME) duration = duration - freeTime * 60 c = Caculater(duration, package) money = c.caculate() if maxConsume == DefaultParams.DEFAULT_MAX_CONSUME: return money return min(money, RMB(maxConsume)) def get_parkingInfo(self): serviceInfo = HuopoCacheMgr.get_parking_cache(self.device.groupId) parkingInfo = {} if serviceInfo is not None: parkingInfo = serviceInfo.get("parkingInfo", {}) return parkingInfo def start_device(self, package, openId, attachParas): """启动 不把扣费逻辑做到这里面,是否决定扣费由外层service来决定 """ # 获取开闸信号 和 进入出门 # TODO 标记用户的control不见了 chargeIndex = attachParas.get("chargeIndex") control = "exit" if chargeIndex == "1" else "enter" # 开启道闸 result = self._open() # 获取用户是否是VIP,使用了虚拟卡支付的都是VIP if self._vcard_id: _key = "VIPMaxParking" else: _key = "maxParking" # 在设备启动时候已经 加了锁 对于该设备当前 parkingInfo = self.get_parkingInfo() parkingNum = parkingInfo.get(_key, 0) if control == "exit": if parkingNum > 0: parkingNum -= 1 elif control == "enter": parkingNum += 1 # 更新当前的最大人数 扫码的VIP不限制 if openId and _key == "VIPMaxParking": parkingInfo.update({_key: parkingNum}) HuopoCacheMgr.set_parking_cache(self._device.groupId, {"parkingInfo": parkingInfo}) return result def notify_user(self, order, cardStart=False): """通知用户订单结束""" logger.info("start notify to user order finished") if order.isNormal and order.finishedTime: # 服务完成的订单需要通知用户 openId = order.openId user = MyUser.objects.filter(openId=openId, groupId=self._device['groupId']).first() dealerId = self._device["ownerId"] group = Group.get_group(self._device["groupId"]) address = group.get("address", "") startType = u"刷卡启动" if cardStart else u"扫码启动" # 通知的时候告诉用户是否使用虚拟卡支付了此次的费用 判断依据是 attachParas 里面有没有 vCardId if not order.attachParas.get("vCardId") and not order.attachParas.get("cardId"): payType = u"账户余额支付" elif not order.attachParas.get("vCardId") and order.attachParas.get("cardId"): payType = u"卡余额支付" else: payType = u"虚拟卡支付" consumeDict = { "title": u"\\n\\n设备编号:\\t\\t{logicalCode}\\n\\n服务地址:\\t\\t{group}\\n\\n起始时间:\\t\\t{st}\\n\\n结束时间:\\t\\t{et}\\n\\n启动方式:\\t\\t{startType}\\n\\n支付方式:\\t\\t{payType}".format( logicalCode=order.logicalCode, group=address, st=order.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S"), et=order.finishedTime.strftime("%Y-%m-%d %H:%M:%S"), startType=startType, payType=payType ), "service": u"停车服务已经结束", "finishTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "remark": u"谢谢您的支持" } task_caller( 'report_to_user_via_wechat', openId=user.managerialOpenId if user else "", dealerId=dealerId, templateName="service_complete", **consumeDict ) def analyze_event_data(self, data): """ 刷卡上报事件 #2181113205,1,0010967430@ #{sn号},{读头号(固定为1)},{刷卡卡号}@ 返回数据 {"cmd":221,"IMEI":"866289037458447","funCode":"","data":"#2181113205,B1@"} """ snNum, dutou, cardNoStr = data.replace("#", "").replace("@", "").split(",") cardNo = str(int(cardNoStr)) return {"snNum": snNum, "cardNo": cardNo, "cardNoStr": cardNoStr, "dutou": dutou} def is_port_can_use(self, chargeIndex, canAdd=None): """这个地方不做判断 直接通过, 具体的停车人数在启动的时候对其进行判断,以免用户在扫码界面停留过久""" return True, u"" def get_dev_setting(self): deviceConf = self._get_device_config() serverConf = self._get_server_config() conf = dict() conf.update(deviceConf) conf.update(serverConf) return conf def set_device_function_param(self, request, lastSetConf): """lastSetConf 缓存中的配置,更新的同时更新缓存""" maxConsume = int(request.POST.get("maxConsume")) cardWait = int(request.POST.get("cardWait")) freeTime = int(request.POST.get("freeTime")) maxParking = int(request.POST.get("maxParking")) vipMaxParking = int(request.POST.get("VIPMaxParking")) snNum = str(request.POST.get("snNum")) if snNum == DefaultParams.DEFAULT_SN_NUM: raise ServiceException({"result": "2", "description": u"保存失败,请配置主板编号"}) # 配置驱动侧参数 self._set_card_wait(cardWait) otherConf = self.device.get("otherConf", dict()) otherConf.update({ "maxConsume": maxConsume, "cardWait": cardWait, "freeTime": freeTime, "maxParking": maxParking, "VIPMaxParking": vipMaxParking, "snNum": snNum }) Device.objects.filter(devNo=self.device.devNo).update(otherConf=otherConf) Device.invalid_device_cache(devNo=self.device.devNo)